Skip to content

Describe the resource in the adapter and cast expressions with it - #2448

Draft
Flo0807 wants to merge 1 commit into
feature/generic-filtersfrom
feature/describe-resource
Draft

Flo0807 wants to merge 1 commit into
feature/generic-filtersfrom
feature/describe-resource

Conversation

@Flo0807

@Flo0807 Flo0807 commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Stack (merge in this order)

  1. Build queries only in the Ecto adapter #2338 Build queries only in the Ecto adapter, based on develop
  2. Let the adapter turn filter conditions and metric aggregates into queries #2340 Let the adapter turn filter conditions and metric aggregates into queries
  3. Configure filters in the LiveResource like fields #2431 Configure filters in the LiveResource like fields
  4. Describe the resource in the adapter and cast expressions with it #2448 Describe the resource in the adapter and cast expressions with it ← this PR
  5. Read through a Backpex.Query #2449 Read through a Backpex.Query
  6. Apply the parts of a query an adapter doesn't run in memory #2450 Apply the parts of a query an adapter doesn't run in memory
  7. Write through neutral changes and let adapters declare writes #2451 Write through neutral changes and let adapters declare writes
  8. Replace item_query, :select and :custom_alias with scope, load and computed values #2454 Replace item_query, :select and :custom_alias with scope, load and computed values
  9. Compute aggregates of related items #2455 Compute aggregates of related items

Second step of the adapter-neutral data access after the expressions of #2340: the adapter describes the resource, and Backpex checks and casts expressions with that description, so an adapter gets values of the right type and a typo in a filter fails with a clear message.

describe/2 replaces association/2 and field_type/2

  • New adapter callback c:Backpex.Adapter.describe/2. It returns a Backpex.Adapter.Description of the items of the resource, or, with a path of relationships such as [:author], of the related items at its end, or nil for an unknown path:
    • :primary_key - the names of the fields of the primary key.
    • :fields - a map of field names to their :type (an Ecto type such as :integer or Ecto.Enum, which an adapter for another data source maps its types to) and :primitive type.
    • :relationships - the maps association/2 returned: :field, :cardinality, :owner_key and :through.
  • Backpex.Resource.describe/2 calls it. Backpex.Resource.association/2 and Backpex.Resource.field_type/2 stay as helpers that read the description, so BelongsTo, HasManyThrough, default_attrs/3 and the Range filter are unchanged.
  • The Ecto adapter describes the schema with __schema__/1,2, also at the end of through associations.

Expressions are checked and cast

  • Backpex.Expr.cast/2 checks the fields of an expression against the description: unknown fields, unknown relationships and paths through relationships to many items raise an ArgumentError that names the field. It casts the values of comparisons and of in to the types of their fields, e.g. expr(likes >= "10") becomes expr(likes >= 10) and expr(role == "admin") becomes expr(role == :admin) for an Ecto.Enum, also on paths and inside exists/2. A value that can't be cast is kept, so the adapter decides about it. Parts of strings (contains/2 and friends) and native expressions are kept.
  • The core only uses Ecto.Changeset for casting, as the adapter boundary test requires.
  • The Ecto adapter casts the expressions of filters and of the :where of metrics with Backpex.Resource.cast_expr/2. Backpex.Adapters.Ecto.apply_filters/5 takes the LiveResource for that; apply_filters/4 keeps working without casting.

Breaking changes (v0.25 upgrade guide)

  • Custom adapters implement describe/2 instead of association/2 and the optional field_type/2, and should pass expressions to Backpex.Resource.cast_expr/2.
  • A filter or metric expression with an unknown field raises when the index view applies it, with the name of the field.

Not in this PR

Testing

  • mix test incl. integration_test/ 1449 passed (182 doctests), mix test --only e2e 60 passed, mix compile --warnings-as-errors --force, mix format --check-formatted, mix credo, mix docs without warnings, mix deps.unlock --check-unused and mix gettext.extract --check-up-to-date pass.
  • New: unit tests of Backpex.Expr.cast/2 with a fake description (casting, parameterized types, paths, exists, kept values, errors), describe/2 tests of the Ecto adapter (fields, associations, through associations, paths), and integration tests that cast with a LiveResource against PostgreSQL.
  • Demo: 51 tests, the 38 Playwright tests and bun run lint pass.

@codecov

codecov Bot commented Nov 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

- Describe the resource in the adapter and cast expressions with it
- Refer to before_changeset/6 of v0.24 without a link
@Flo0807
Flo0807 force-pushed the feature/describe-resource branch from 0b54c27 to d7e1096 Compare November 13, 2026 09:46

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change A breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant