Cinder.QueryBuilder (Cinder v0.8.1)
View SourceQuery building functionality for Cinder table components.
Handles the construction of Ash queries with filters, sorting, and pagination for table data loading.
Summary
Functions
Applies filters to an Ash query based on filter configuration and column definitions.
Applies query options like load and select to an Ash query.
Applies global search to an Ash query across searchable columns.
Applies sorting to an Ash query based on sort specifications.
Applies standard filters by delegating to the appropriate filter module.
Builds a complete query with filters, sorting, and pagination.
Builds error pagination info for failed queries.
Builds pagination info from query results and total count.
Determines if a calculation can be sorted at the database level.
Extracts sort information from an Ash query for table UI initialization.
Checks if a field exists on a resource (including attributes, relationships, calculations, aggregates)
Retrieves calculation information for a given field from an Ash resource.
Gets the current sort direction for a given key.
Resolves a field to its target resource and field name. Handles relationship traversal (e.g., "user.profile.first_name" -> {Profile, "first_name"})
Toggles sort direction for a given key in the sort specification.
Toggles sort direction with special handling for query-extracted sorts.
Toggles sort direction using custom cycle configuration.
Validates field existence on a resource, handling all field types including embedded fields.
Validates that all fields in a sort list can be sorted at the database level.
Types
Functions
Applies filters to an Ash query based on filter configuration and column definitions.
Applies query options like load and select to an Ash query.
Warns if unsupported options are provided.
Applies global search to an Ash query across searchable columns.
Parameters
query: The Ash query to modifysearch_term: The search term to filter by (empty/nil terms are ignored)columns: List of column definitions to find searchable fieldscustom_search_fn: Optional table-level custom search function
Custom Search Function Signature
search_fn(query, searchable_columns, search_term)
Returns
The modified query with search conditions applied, or the original query if no search term is provided or no searchable columns exist.
Examples
# Default search across searchable columns
query = apply_search(query, "widget", columns, nil)
# Custom search function
def custom_search(query, searchable_columns, search_term) do
# Custom implementation
end
query = apply_search(query, "widget", columns, &custom_search/3)
Applies sorting to an Ash query based on sort specifications.
Applies standard filters by delegating to the appropriate filter module.
Builds a complete query with filters, sorting, and pagination.
Parameters
resource_or_query: The Ash resource to query or a pre-built Ash.Queryoptions: Query building options including::actor- The current user/actor:filters- Filter map:sort_by- Sort specifications:page_size- Number of records per page:current_page- Current page number:columns- Column definitions:query_opts- Additional Ash query and execution options:search_term- Global search term to search across searchable columns:search_fn- Optional custom search function with signature(query, searchable_columns, search_term)
Supported Query Options
The :query_opts parameter accepts both query building and execution options:
Query Building Options
:select- Select specific attributes (handled byAsh.Query.select/2):load- Load relationships and calculations (handled byAsh.Query.load/2)
Execution Options
These options are passed to both Ash.Query.for_read/3 and Ash.read/2:
:timeout- Query timeout in milliseconds or:infinity(e.g.,:timer.seconds(30)):authorize?- Whether to run authorization during query execution:max_concurrency- Maximum number of processes for parallel loading
Usage Examples
# Simple timeout for long-running queries
query_opts: [timeout: :timer.seconds(30)]
# Query building options
query_opts: [select: [:name, :email], load: [:posts]]
# Combined query building and execution options
query_opts: [
timeout: :timer.seconds(20),
authorize?: false,
select: [:title, :content],
load: [:author, :comments]
]Returns
A tuple {:ok, {results, page_info}} or {:error, reason}
Builds error pagination info for failed queries.
Builds pagination info from query results and total count.
Determines if a calculation can be sorted at the database level.
Checks if a calculation has an expression/2 function that allows it to be
converted to a database expression for sorting.
Parameters
calculation- An Ash calculation struct
Returns
trueif the calculation can be sorted at the database levelfalseif the calculation is computed in-memory and cannot be sorted
Examples
# Database-level calculation (using expr())
calculation_sortable?(%{calculation: {Ash.Resource.Calculation.Expression, _}})
# => true
# In-memory calculation without expression/2
calculation_sortable?(%{calculation: {MyCalcModule, _}})
# => false (if MyCalcModule doesn't implement expression/2)
Extracts sort information from an Ash query for table UI initialization.
Takes an Ash query and returns sort information in the format expected by
the table component: [{field_name, direction}]
Parameters
query- An Ash.Query struct or resource modulecolumns- Column definitions to map query sorts to table fields
Returns
A list of {field_name, direction} tuples where:
field_nameis a string matching table column field namesdirectionis:ascor:desc
Examples
# Query with sorts
query = User |> Ash.Query.for_read(:read) |> Ash.Query.sort([{:name, :desc}, {:created_at, :asc}])
extract_query_sorts(query, columns)
# => [{"name", :desc}, {"created_at", :asc}]
# Resource module (no sorts)
extract_query_sorts(User, columns)
# => []
Checks if a field exists on a resource (including attributes, relationships, calculations, aggregates)
Retrieves calculation information for a given field from an Ash resource.
Parameters
resource- Ash resource modulefield_name- Field name as atom or string
Returns
- Calculation struct if the field is a calculation
nilif the field is not a calculation or doesn't exist
Examples
get_calculation_info(User, :full_name)
# => %{name: :full_name, calculation: {...}, ...} or nil
Gets the current sort direction for a given key.
Resolves a field to its target resource and field name. Handles relationship traversal (e.g., "user.profile.first_name" -> {Profile, "first_name"})
Toggles sort direction for a given key in the sort specification.
Provides a predictable three-step cycle:
- none → ascending → descending → none
When starting with extracted query sorts, use toggle_sort_from_query/2
for better UX that handles the transition from query state to user control.
Toggles sort direction with special handling for query-extracted sorts.
When a column has a sort from query extraction, the first user click provides intuitive behavior:
- desc (from query) → asc (user takes control)
- asc (from query) → desc (user takes control)
After first click, follows standard toggle cycle.
Toggles sort direction using custom cycle configuration.
Supports custom sort cycles like [nil, :desc_nils_last, :asc_nils_first].
Falls back to standard toggle_sort_direction/2 if no custom cycle provided.
Validates field existence on a resource, handling all field types including embedded fields.
Supports:
- Direct fields: "name"
- Relationship fields: "user.profile.name"
- Embedded fields: "profile__first_name" (URL-safe) or "profile[:first_name]" (bracket notation)
- Mixed fields: "user.profileaddressstreet"
Validates that all fields in a sort list can be sorted at the database level.
Checks each sort field to ensure it's not an in-memory calculation that would cause crashes or undefined behavior when sorting is attempted.
Parameters
sort_by- List of{field, direction}tuplesresource- Ash resource module
Returns
:okif all fields can be sorted{:error, message}if any fields cannot be sorted
Examples
validate_sortable_fields([{"name", :asc}], User)
# => :ok
validate_sortable_fields([{"in_memory_calc", :asc}], User)
# => {:error, "Cannot sort by in-memory calculations..."}