Aurora.Ctx.Core (Aurora.Ctx v0.1.9)
View SourceProvides comprehensive database operations using Ecto with advanced query building, pagination, and CRUD functionality.
This module serves as the core interface for database operations, offering:
- CRUD Operations: Create, read, update, and delete records with flexible changeset support
- Advanced Pagination: Navigate through large datasets with configurable page sizes and safe boundary handling
- Query Building: Filter, sort, and preload associations using
Aurora.Ctx.QueryBuilderoptions - Record Management: Initialize new records and build changesets with custom functions
- Query Utilities: Count records and exclude specific query clauses
Configuration
Default pagination settings can be configured in your application:
config :aurora_ctx, :paginate,
page: 1,
per_page: 40Query Options
Most functions accept query options that are processed by Aurora.Ctx.QueryBuilder:
where: keyword()- Filter conditionsorder_by: keyword()- Sorting specificationspreload: atom() | list()- Associations to preloadpaginate: map()- Pagination parametersselect: list()- List of fields to load
Examples
alias MyApp.{Repo, Product, Category}
# List all products with filtering and preloading
products = Core.list(Repo, Product,
where: [status: :active],
order_by: [desc: :inserted_at],
preload: [:category]
)
# Paginated listing with navigation
page1 = Core.list_paginated(Repo, Product,
paginate: %{page: 1, per_page: 20},
where: [category_id: 1]
)
page2 = Core.next_page(page1)
# CRUD operations
{:ok, product} = Core.create(Repo, Product, %{name: "Widget", price: 99.99})
{:ok, updated} = Core.update(Repo, product, %{price: 89.99})
{:ok, _deleted} = Core.delete(Repo, updated)
Summary
Functions
Creates a changeset for the given entity using the default changeset function.
Creates a changeset for the given entity using a specific changeset function.
Counts total records matching the specified query conditions.
Creates a new record using the default changeset function.
Creates a new record with a custom changeset function.
Creates a new record using the default changeset function, raising on errors.
Creates a new record with a custom changeset function, raising on errors.
Deletes the given entity from the database.
Deletes the given entity from the database, raising on errors.
Excludes specific query clauses from an Ecto query.
Gets a single record by its primary key.
Gets a single record by its primary key, raising if not found.
Gets a single record by filtering clauses.
Gets a single record by filtering clauses, raising if not found or multiple found.
Lists all records for a schema with optional filtering and sorting.
Lists records with pagination metadata.
Initializes a new schema struct with optional attributes.
Initializes a new schema struct with attributes and optional preloads.
Moves to the next page in paginated results.
Moves to the previous page in paginated results.
Navigates to a specific page in paginated results.
Updates an entity with given attributes using the default changeset function.
Updates an entity using a specific changeset function.
Functions
@spec change(Ecto.Schema.t() | Ecto.Changeset.t(), map()) :: Ecto.Changeset.t()
Creates a changeset for the given entity using the default changeset function.
Convenience function that calls change/3 with the default :changeset
function and provided attributes.
Parameters
entity_or_changeset(Ecto.Schema.t() | Ecto.Changeset.t()) - Existing record or changeset to create changeset fromattrs(map()) - Changeset attributes
Returns
Ecto.Changeset.t() - Changeset with applied attributes and validations
Examples
product = %Product{name: "Widget"}
changeset = Core.change(product, %{name: "New Widget", price: 99.99})
#=> #Ecto.Changeset<changes: %{name: "New Widget", price: 99.99}>
@spec change(Ecto.Schema.t() | Ecto.Changeset.t(), atom() | function(), map()) :: Ecto.Changeset.t()
Creates a changeset for the given entity using a specific changeset function.
Provides flexibility to use custom changeset functions for specialized validation or transformation logic when building changesets.
Parameters
entity_or_changeset(Ecto.Schema.t() | Ecto.Changeset.t()) - Existing record or changeset to create changeset fromchangeset_function(atom() | function()) - Changeset function to apply:atom()- Function name assumed to exist in the schema modulefunction()- Direct function reference with arity 2
attrs(map()) - Changeset attributes
Returns
Ecto.Changeset.t() - Changeset with applied attributes and validations
Examples
product = %Product{name: "Widget"}
changeset = Core.change(product, :update_changeset, %{price: 89.99})
#=> #Ecto.Changeset<changes: %{price: 89.99}>
# Using function reference
custom_fn = &Product.custom_changeset/2
changeset = Core.change(product, custom_fn, %{status: :active})
#=> #Ecto.Changeset<changes: %{status: :active}>
@spec count(module(), module(), keyword()) :: non_neg_integer()
Counts total records matching the specified query conditions.
Efficiently counts records by excluding unnecessary query clauses like select, limit, offset, and order_by that don't affect the count result.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryopts(keyword()) - Query filtering options supported byAurora.Ctx.QueryBuilder
Returns
non_neg_integer() - Total count of records matching the query conditions
Examples
# Count all products
Core.count(Repo, Product)
#=> 1250
# Count with filtering
Core.count(Repo, Product, where: [status: :active, category_id: 1])
#=> 45
@spec create(module(), module() | Ecto.Changeset.t(), map()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Creates a new record using the default changeset function.
Convenience function that calls create/4 with the default :changeset
function and provided attributes.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module_or_changeset(module() | Ecto.Changeset.t()) - Schema module or existing changeset to create fromattrs(map()) - Attributes for the new record
Returns
{:ok, Ecto.Schema.t()}- Successfully created record{:error, Ecto.Changeset.t()}- Validation or constraint errors
Examples
# Create with schema module
Core.create(Repo, Product, %{name: "Widget", price: 99.99})
#=> {:ok, %Product{name: "Widget", price: 99.99}}
# Create with existing changeset
changeset = Product.changeset(%Product{}, %{name: "Gadget"})
Core.create(Repo, changeset, %{price: 49.99})
#=> {:ok, %Product{name: "Gadget", price: 49.99}}
@spec create(module(), module() | Ecto.Changeset.t(), atom() | function(), map()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Creates a new record with a custom changeset function.
Provides flexibility to use custom changeset functions for specialized validation or transformation logic during record creation.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module() | Ecto.Changeset.t()) - Schema module or existing changeset to create fromchangeset_function(atom() | function()) - Changeset function to apply:atom()- Function name assumed to exist in the schema modulefunction()- Direct function reference with arity 2
attrs(map()) - Attributes for the new record
Returns
{:ok, Ecto.Schema.t()}- Successfully created record{:error, Ecto.Changeset.t()}- Validation or constraint errors
Examples
# Using custom changeset function by name
Core.create(Repo, Product, :registration_changeset, %{
name: "Widget",
code: "WDG001"
})
#=> {:ok, %Product{name: "Widget", code: "WDG001"}}
# Using function reference
custom_fn = &Product.custom_changeset/2
Core.create(Repo, Product, custom_fn, %{name: "Gadget"})
#=> {:ok, %Product{name: "Gadget"}}
@spec create!(module(), module() | Ecto.Changeset.t(), map()) :: Ecto.Schema.t()
Creates a new record using the default changeset function, raising on errors.
Convenience function that calls create!/4 with the default :changeset
function and provided attributes.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module_or_changeset(module() | Ecto.Changeset.t()) - Schema module or existing changeset to create fromattrs(map()) - Attributes for the new record
Returns
Ecto.Schema.t() - Successfully created record
Raises
Ecto.InvalidChangesetError- Invalid changeset dataEcto.ConstraintError- Database constraint violations
Examples
product = Core.create!(Repo, Product, %{name: "Widget", price: 99.99})
#=> %Product{name: "Widget", price: 99.99}
@spec create!(module(), module() | Ecto.Changeset.t(), atom() | function(), map()) :: Ecto.Schema.t()
Creates a new record with a custom changeset function, raising on errors.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module_or_changeset(module() | Ecto.Changeset.t()) - Schema module or existing changeset to create fromchangeset_function(atom() | function()) - Changeset function to apply:atom()- Function name assumed to exist in the schema modulefunction()- Direct function reference with arity 2
attrs(map()) - Attributes for the new record
Returns
Ecto.Schema.t() - Successfully created record
Raises
Ecto.InvalidChangesetError- Invalid changeset dataEcto.ConstraintError- Database constraint violations
Examples
product = Core.create!(Repo, Product, :registration_changeset, %{
name: "Widget",
code: "WDG001"
})
#=> %Product{name: "Widget", code: "WDG001"}
@spec delete(module(), Ecto.Schema.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Deletes the given entity from the database.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsentity(Ecto.Schema.t()) - Entity struct to delete
Returns
{:ok, Ecto.Schema.t()}- Successfully deleted entity{:error, Ecto.Changeset.t()}- Delete operation failed
Examples
product = Core.get!(Repo, Product, 123)
{:ok, deleted_product} = Core.delete(Repo, product)
#=> {:ok, %Product{id: 123, ...}}
@spec delete!(module(), Ecto.Schema.t()) :: Ecto.Schema.t()
Deletes the given entity from the database, raising on errors.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsentity(Ecto.Schema.t()) - Entity struct to delete
Returns
Ecto.Schema.t() - Successfully deleted entity
Raises
Ecto.StaleEntryError - Entity has been modified or deleted by another process
Examples
product = Core.get!(Repo, Product, 123)
deleted_product = Core.delete!(Repo, product)
#=> %Product{id: 123, ...}
@spec exclude_clauses(Ecto.Query.t(), atom() | [atom()]) :: Ecto.Query.t()
Excludes specific query clauses from an Ecto query.
Removes unwanted clauses from a query, which is useful for operations like counting where certain clauses (select, limit, offset, order_by) are not needed and may interfere with the operation.
Parameters
query(Ecto.Query.t()) - Query to modify by excluding clausesclauses(atom() | list(atom())) - Clause(s) to exclude. Available clauses::where- WHERE conditions:select- SELECT clauses:order_by- ORDER BY clauses:group_by- GROUP BY clauses:having- HAVING conditions:limit- LIMIT clause:offset- OFFSET clause:preload- Preload associations:lock- Lock clauses
Returns
Ecto.Query.t() - Modified query with specified clauses excluded
Examples
query = from(p in Product, where: p.status == :active, order_by: p.name)
# Exclude single clause
exclude_clauses(query, :order_by)
#=> query without ORDER BY clause
# Exclude multiple clauses
exclude_clauses(query, [:select, :order_by, :limit])
#=> query without SELECT, ORDER BY, or LIMIT clauses
@spec get(module(), module(), term(), keyword()) :: Ecto.Schema.t() | nil
Gets a single record by its primary key.
Supports additional query options for preloading associations and other
query modifications processed by Aurora.Ctx.QueryBuilder.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryid(term()) - Primary key value to look upopts(keyword()) - Query options:preload: atom() | list()- Associations to preload- Plus other options supported by
Aurora.Ctx.QueryBuilder
Returns
Ecto.Schema.t()- Found recordnil- No record found with the given primary key
Examples
# Get by ID
Core.get(Repo, Product, 123)
#=> %Product{id: 123, name: "Widget"}
# Get with preloaded associations
Core.get(Repo, Product, 123, preload: [:category, :reviews])
#=> %Product{id: 123, category: %Category{}, reviews: [%Review{}]}
@spec get!(module(), module(), term(), keyword()) :: Ecto.Schema.t()
Gets a single record by its primary key, raising if not found.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryid(term()) - Primary key value to look upopts(keyword()) - Query options supported byAurora.Ctx.QueryBuilder
Returns
Ecto.Schema.t() - Found record
Raises
Ecto.NoResultsError - No record found with the given primary key
Examples
product = Core.get!(Repo, Product, 123)
#=> %Product{id: 123, name: "Widget"}
Core.get!(Repo, Product, 999)
#=> ** (Ecto.NoResultsError)
@spec get_by(module(), module(), keyword(), keyword()) :: Ecto.Schema.t() | nil
Gets a single record by filtering clauses.
Finds the first record matching the given clauses. If multiple records match,
only the first one is returned. Use get_by!/4 for strict single-result
enforcement.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryclauses(keyword()) - Filter conditions as key-value pairsopts(keyword()) - Query options supported byAurora.Ctx.QueryBuilder
Returns
Ecto.Schema.t()- First matching recordnil- No record matches the given clauses
Examples
# Get by single field
Core.get_by(Repo, Product, name: "Widget")
#=> %Product{name: "Widget"}
# Get by multiple fields
Core.get_by(Repo, Product, [name: "Widget", status: :active])
#=> %Product{name: "Widget", status: :active}
# With preloading
Core.get_by(Repo, Product, [code: "WDG001"], preload: [:category])
#=> %Product{code: "WDG001", category: %Category{}}
@spec get_by!(module(), module(), keyword(), keyword()) :: Ecto.Schema.t()
Gets a single record by filtering clauses, raising if not found or multiple found.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryclauses(keyword()) - Filter conditions as key-value pairsopts(keyword()) - Query options supported byAurora.Ctx.QueryBuilder
Returns
Ecto.Schema.t() - The unique matching record
Raises
Ecto.NoResultsError- No record matches the given clausesEcto.MultipleResultsError- Multiple records match the given clauses
Examples
product = Core.get_by!(Repo, Product, code: "WDG001")
#=> %Product{code: "WDG001"}
Core.get_by!(Repo, Product, name: "NonExistent")
#=> ** (Ecto.NoResultsError)
@spec list(module(), module(), keyword()) :: [Ecto.Schema.t()]
Lists all records for a schema with optional filtering and sorting.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryopts(keyword()) - Query options processed byAurora.Ctx.QueryBuilder:where: keyword()- Filter conditionsorder_by: keyword()- Sorting specificationspreload: atom() | list()- Associations to preloadselect: list()- List of fields to load
Returns
list(Ecto.Schema.t()) - List of records as schema structs matching the query conditions
Examples
alias MyApp.{Repo, Product}
# List all products
Core.list(Repo, Product)
#=> [%Product{}, ...]
# List with filtering, sorting, and preloading
Core.list(Repo, Product,
where: [status: :active],
order_by: [desc: :inserted_at],
preload: [:category]
)
#=> [%Product{category: %Category{}}, ...]
@spec list_paginated(module(), module(), keyword()) :: Aurora.Ctx.Pagination.t()
Lists records with pagination metadata.
Returns a Pagination struct containing the current page entries along with
metadata for browsing. Page boundaries are safely handled - attempting to
navigate beyond valid pages returns the current page with its entries refreshed.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsschema_module(module()) - Schema module to queryopts(keyword()) - Query and pagination options:paginate: map()- Pagination configuration withpageandper_pagekeys- Plus all options supported by
Aurora.Ctx.QueryBuilder
Returns
Aurora.Ctx.Pagination.t() - Pagination struct, see Aurora.Ctx.Pagination
Examples
alias MyApp.{Repo, Product}
# Basic pagination
page1 = Core.list_paginated(Repo, Product,
paginate: %{page: 1, per_page: 20}
)
#=> %Aurora.Ctx.Pagination{
#=> entries: [%Product{}],
#=> page: 1,
#=> per_page: 20,
#=> entries_count: 150,
#=> pages_count: 8
#=> }
# With filtering and sorting
Core.list_paginated(Repo, Product,
paginate: %{page: 2, per_page: 10},
where: [category_id: 1],
order_by: [desc: :inserted_at]
)
@spec new(module(), module(), map() | keyword()) :: Ecto.Schema.t()
Initializes a new schema struct with optional attributes.
Convenience function that calls new/4 with empty options when provided
with a map of attributes, or calls new/4 with empty attributes when
provided with a keyword list of options.
Parameters
repo_module(module()) - Ecto.Repo module to use for potential preloadingschema_module(module()) - Schema module to initializeattrs_or_opts- Either:map()- Initial attributes (will use empty options)keyword()- Options including preload specifications (will use empty attributes)
Returns
Ecto.Schema.t() - Initialized schema struct
Examples
# Initialize with attributes
product = Core.new(Repo, Product, %{name: "Widget", price: 99.99})
#=> %Product{name: "Widget", price: 99.99}
# Initialize with preload options
product = Core.new(Repo, Product, preload: [:category])
#=> %Product{category: %Category{}}
@spec new(module(), module(), map(), keyword()) :: Ecto.Schema.t()
Initializes a new schema struct with attributes and optional preloads.
Creates a new struct instance and optionally preloads specified associations. Useful for preparing new records with related data for forms or other operations.
Parameters
repo_module(module()) - Ecto.Repo module to use for preloading operationsschema_module(module()) - Schema module to initializeattrs(map()) - Initial attributes to set on the structopts(keyword()) - Options:preload: atom() | list()- Associations to preload
Returns
Ecto.Schema.t() - Initialized schema struct with preloaded associations
Examples
# Basic initialization
product = Core.new(Repo, Product, %{name: "Widget"}, [])
#=> %Product{name: "Widget"}
# With preloaded associations
product = Core.new(Repo, Product, %{name: "Widget"}, preload: [:category])
#=> %Product{name: "Widget", category: %Category{}}
@spec next_page(Aurora.Ctx.Pagination.t()) :: Aurora.Ctx.Pagination.t()
Moves to the next page in paginated results.
Safely advances to the next page if available. If already on the last page, returns the current pagination state with its entries refreshed.
Parameters
paginate(Aurora.Ctx.Pagination.t()) - Current pagination state
Returns
Aurora.Ctx.Pagination.t() - Pagination struct for the next page or current
page if already at the end
Examples
page1 = Core.list_paginated(Repo, Product, paginate: %{page: 1, per_page: 20})
page2 = Core.next_page(page1)
#=> %Aurora.Ctx.Pagination{page: 2, entries: [...]}
@spec previous_page(Aurora.Ctx.Pagination.t()) :: Aurora.Ctx.Pagination.t()
Moves to the previous page in paginated results.
Safely moves back to the previous page if available. If already on the first page, returns the current pagination state with its entries refreshed.
Parameters
paginate(Aurora.Ctx.Pagination.t()) - Current pagination state
Returns
Aurora.Ctx.Pagination.t() - Pagination struct for the previous page or
current page refreshed if already at the beginning
Examples
page3 = Core.list_paginated(Repo, Product, paginate: %{page: 3, per_page: 20})
page2 = Core.previous_page(page3)
#=> %Aurora.Ctx.Pagination{page: 2, entries: [...]}
@spec to_page(Aurora.Ctx.Pagination.t(), integer()) :: Aurora.Ctx.Pagination.t()
Navigates to a specific page in paginated results.
Provides safe navigation by validating the target page is within valid bounds. If the requested page is out of range (< 1 or > pages_count), returns the current pagination state with its entries updated.
Parameters
paginate(Aurora.Ctx.Pagination.t()) - Current pagination state containing repo module, schema, and query optionspage(integer()) - Target page number to navigate to
Returns
Aurora.Ctx.Pagination.t() - Updated pagination struct with entries for the
target page
Examples
paginate = Core.list_paginated(Repo, Product, paginate: %{per_page: 20})
# Navigate to page 5
page5 = Core.to_page(paginate, 5)
#=> %Aurora.Ctx.Pagination{page: 5, entries: [...]}
# Out of range navigation returns current page with its entries updated
same_page = Core.to_page(paginate, 999)
#=> %Aurora.Ctx.Pagination{page: 1, entries: [...]} (unchanged)
@spec update(module(), Ecto.Schema.t() | Ecto.Changeset.t(), map()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Updates an entity with given attributes using the default changeset function.
Convenience function that calls update/4 with the default :changeset
function and provided attributes.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsentity_or_changeset(Ecto.Schema.t() | Ecto.Changeset.t()) - Existing record to update or changeset to applyattrs(map()) - Update attributes
Returns
{:ok, Ecto.Schema.t()}- Successfully updated record{:error, Ecto.Changeset.t()}- Validation or constraint errors
Examples
product = Core.get!(Repo, Product, 123)
{:ok, updated} = Core.update(Repo, product, %{name: "New Name", price: 89.99})
#=> {:ok, %Product{name: "New Name", price: 89.99}}
@spec update( module(), Ecto.Schema.t() | Ecto.Changeset.t(), atom() | function(), map() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Updates an entity using a specific changeset function.
Provides flexibility to use custom changeset functions for specialized validation or transformation logic during record updates.
Parameters
repo_module(module()) - Ecto.Repo module to use for database operationsentity_or_changeset(Ecto.Schema.t() | Ecto.Changeset.t()) - Existing record to update or changeset to applychangeset_function(atom() | function()) - Changeset function to apply:atom()- Function name assumed to exist in the schema modulefunction()- Direct function reference with arity 2
attrs(map()) - Update attributes
Returns
{:ok, Ecto.Schema.t()}- Successfully updated record{:error, Ecto.Changeset.t()}- Validation or constraint errors
Examples
product = Core.get!(Repo, Product, 123)
{:ok, updated} = Core.update(Repo, product, :update_changeset, %{
price: 79.99,
updated_reason: "Price adjustment"
})
#=> {:ok, %Product{price: 79.99, updated_reason: "Price adjustment"}}