You could use an action like this:
# sets the position and reorders
update :move_position do
accept [:position]
change YourResource.Changes.RepositionAll
end
update :decrement_position do
change atomic_update(:position, position - 1)
end
update :increment_position do
change atomic_update(:position, position - 1)
end
Some adaptation of the code you linked:
defmodule YourResource.Changes.RepositionAll do
use Ash.Resource.Change
require Ash.Query
import Ash.Expr
def change(changeset, opts, _) do
changeset
|> Ash.Changeset.before_action(changeset, fn changeset ->
requested_position = Ash.Changeset.get_attribute(changeset, :position)
max_position =
resource
# put in whatever grouping you're sorting these within
|> Ash.Query.filter(group_id == ^Ash.Changeset.get_attribute(changeset, :group_id))
|> Ash.count!()
new_position = min(requested_position, max_position)
id = Ash.Changeset.get_attribute(changeset, :id)
with %Ash.BulkResult{status: :succes} <- shift_down(id, new_position),
%Ash.BulkResult{status: :succes} <- shift_up(id, new_position) do
changeset
else
%Ash.BulkResult{errors: errors} -> Ash.Changeset.add_error(changeset, errors)
end
end)
end
def shift_down(resource, id, new_position) do
resource
|> Ash.Query.filter(position > ^old_position(id) and position <= new_position)
|> Ash.Query.bulk_update!(:decrement_position)
end
def shift_up(id, new_position) do
resource
|> Ash.Query.filter(position < ^old_position(id) and position > new_position)
|> Ash.Query.bulk_update!(:decrement_position)
end
def old_position(id) do
expr(fragment("SELECT position FROM table WHERE id = ?", ^id))
end
end
One small note:
old_position = from(og in type, where: og.id == ^struct.id, select: og.position)
stating the above is currently a limitation in Ash expressions, that will be addressed soon: Support resources as aggregate targets in expressions · Issue #939 · ash-project/ash · GitHub
So for that reason, I’ve done it as a SQL fragment, which is not ideal.
I didn’t run any of the above code, but it should be a reasonable place to get started 