Attached.Ecto.CRUD (Attached v0.1.1)

Copy Markdown View Source

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 to Ecto.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 (see maybe_distinct/2 below)
  • :exclude_nil — when true together with :distinct (atom form), filters out rows where that field is nil
  • :query — 1-arity function for ad-hoc query composition, e.g. &Scopes.orphans(&1, "users", "avatar_attached_original_id")
  • :page / :per_pagepaginate/2 only

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

count(schema, opts \\ [])

Counts rows of schema matching the given options.

Accepts the same :query hook as list/2.

get(schema, id, opts \\ [])

Fetches a row of schema by id. Returns nil if not found.

Supports :preload and :query.

get!(schema, id, opts \\ [])

Fetches a row of schema by id. Raises Ecto.NoResultsError if not found.

Supports :preload and :query.

get_by(schema, clauses, opts \\ [])

Fetches a row of schema by the given keyword clauses. Returns nil if not found.

Supports :preload and :query.

list(schema, opts \\ [])

Returns rows of schema matching the given options.

See the module doc for the supported option set.

maybe_distinct(query, field)

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.

maybe_exclude_nil(query, field, arg3)

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.

maybe_limit(query, limit_num)

Conditionally applies a limit clause. No-op when nil.

maybe_offset(query, offset_num)

Conditionally applies an offset clause. No-op when nil.

maybe_order_by(query, order_by_clauses)

Conditionally applies an order_by clause. No-op when nil.

maybe_preload(query, associations)

Conditionally preloads associations. No-op when nil.

maybe_query(queryable, fun)

Conditionally applies a 1-arity query function. No-op when nil.

maybe_select(query, fields)

Conditionally applies a select clause. No-op when nil.

paginate(schema, opts \\ [])

Paginates rows of schema.

Accepts the same :query/:order_by/:preload/:select options as list/2, plus:

  • :page — 1-based page number (default 1)
  • :per_page — items per page (default 25)

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.

validate_opts!(opts, valid_keys)

Validates that all keys in opts are in the valid_keys list.

Raises ArgumentError listing unsupported keys.