Internal, schema-agnostic CRUD helpers used by Attached's context modules.
Generic query plumbing — list, get, get_by, count, paginate —
extracted so context modules stay focused on domain operations (ingest,
purge, orphan detection, owner lookups).
Repo resolution goes through Attached.Repo.current(). This module is
not a generic Ecto CRUD package — it's an internal noise-reduction
pass. If you need a reusable equivalent, see ecto_context.
Composable options
Every function whitelists the options it accepts and raises
ArgumentError on unknown keys. The supported set across all
functions:
:preload— associations to preload:order_by— passed toEcto.Query.order_by/2:limit/:offset— pagination primitives:select— list of fields to select:distinct— atom or list of atoms; turns the query into a distinct-field projection (seemaybe_distinct/2below):exclude_nil— whentruetogether with:distinct(atom form), filters out rows where that field isnil:query— 1-arity function for ad-hoc query composition, e.g.&Scopes.orphans(&1, "users", "avatar_attached_original_id"):page/:per_page—paginate/2only
The :query option is the escape hatch: any
Ecto.Queryable.t() -> Ecto.Queryable.t() function gets threaded
through, so callers can compose library-provided scopes with their
own slicing.
Summary
Functions
Counts rows of schema matching the given options.
Fetches a row of schema by id. Returns nil if not found.
Fetches a row of schema by id. Raises Ecto.NoResultsError if not found.
Fetches a row of schema by the given keyword clauses. Returns nil if not found.
Returns rows of schema matching the given options.
Conditionally turns the query into a distinct-field projection.
Conditionally filters out rows where field is nil.
Conditionally applies a limit clause. No-op when nil.
Conditionally applies an offset clause. No-op when nil.
Conditionally applies an order_by clause. No-op when nil.
Conditionally preloads associations. No-op when nil.
Conditionally applies a 1-arity query function. No-op when nil.
Conditionally applies a select clause. No-op when nil.
Paginates rows of schema.
Validates that all keys in opts are in the valid_keys list.
Functions
Counts rows of schema matching the given options.
Accepts the same :query hook as list/2.
Fetches a row of schema by id. Returns nil if not found.
Supports :preload and :query.
Fetches a row of schema by id. Raises Ecto.NoResultsError if not found.
Supports :preload and :query.
Fetches a row of schema by the given keyword clauses. Returns nil if not found.
Supports :preload and :query.
Returns rows of schema matching the given options.
See the module doc for the supported option set.
Conditionally turns the query into a distinct-field projection.
Forms:
nil— no-op.- atom — selects that field, applies
DISTINCT, orders by it ascending. Returns scalars. Used for dropdown-style lookups. - list of atoms — selects those fields as a map, applies
DISTINCT, orders by them ascending. Returns maps (%{field: value, ...}). Used when you need distinct tuples of multiple columns.
Conditionally filters out rows where field is nil.
Pass true to apply WHERE field IS NOT NULL; anything else is a no-op.
field is an atom column name resolved at runtime.
Conditionally applies a limit clause. No-op when nil.
Conditionally applies an offset clause. No-op when nil.
Conditionally applies an order_by clause. No-op when nil.
Conditionally preloads associations. No-op when nil.
Conditionally applies a 1-arity query function. No-op when nil.
Conditionally applies a select clause. No-op when nil.
Paginates rows of schema.
Accepts the same :query/:order_by/:preload/:select options as
list/2, plus:
:page— 1-based page number (default1):per_page— items per page (default25)
Returns %{entries: [...], total: n, page: p, per_page: pp}.
Internally runs a count/2 and a list/2 with limit + offset
derived from the page.
Validates that all keys in opts are in the valid_keys list.
Raises ArgumentError listing unsupported keys.