PhoenixKit.Utils.Reorder (phoenix_kit v1.7.114)

Copy Markdown View Source

Two-phase index rewrite for drag-to-reorder list views.

Given a list of UUIDs in their new display order and an Ecto schema, rewrites a position field on the matching rows to 1..N matching the order of the input list. The write runs in two passes inside a transaction — first to negative indices, then to positive — so a unique index on the position column (should one ever be added) wouldn't trip mid-update.

Consumers that need pre-write validation (scope checks, permission guards) or post-write side effects (activity logging, PubSub broadcasts) should wrap this helper rather than fold the logic in here. PhoenixKitProjects.reorder_projects/2 is the reference consumer doing exactly that — this module owns only the index-rewrite primitive.

Non-UUID entries in the payload are silently filtered (a stale or malformed drop event can't poison the rewrite). Duplicates dedup last-write-wins via Enum.uniq/1.

Example

defmodule MyApp.Endpoints do
  alias PhoenixKit.Utils.Reorder

  def reorder_endpoints(ordered_ids) do
    Reorder.reorder(MyApp.Endpoint, ordered_ids, :sort_order, repo: repo())
  end
end

Summary

Functions

Rewrites field on the rows whose uuid appears in ordered_ids, setting it to each UUID's 1-based position in the list.

Types

result()

@type result() :: {:ok, non_neg_integer()} | {:error, :too_many_uuids}

Functions

reorder(schema, ordered_ids, field, opts \\ [])

@spec reorder(module(), [String.t()], atom(), keyword()) :: result()

Rewrites field on the rows whose uuid appears in ordered_ids, setting it to each UUID's 1-based position in the list.

Returns {:ok, count} where count is the number of rows actually updated in the positive-write phase (matches Repo.update_all's count semantics — UUIDs in the payload that don't resolve to real rows aren't counted). Returns {:error, :too_many_uuids} when the dedup'd payload exceeds the configured cap. An empty / fully-filtered payload returns {:ok, 0}.

Options

  • :repo — the Ecto repo to use. Defaults to PhoenixKit.RepoHelper.repo/0 so it picks up the host app's repo.
  • :max_uuids — payload cap, checked after dedup. Default 500. Guards against runaway drop events from a misbehaving client.