Source behavior for database-specific operations.
Defines the interface that each database source adapter's operations module must implement.
Summary
Callbacks
Applies a list of filters to an existing query, returning a new query string.
Applies a list of sorts to an existing query, returning a new query string.
Return the list of built-in deny rules for system tables and metadata relations that should be hidden from the schema browser for this source.
Return the list of built-in schema denies that should be hidden from schema listing.
Return the default schemas for this source when no schema options are provided.
Retrieve the execution plan for a SQL query.
Gets the schema information for a specific table.
List the exception modules that this source formats specially in format_error/1.
Return the SQL parameter placeholders for LIMIT and OFFSET clauses.
Lists all schemas in the given repository.
Lists all tables in the given repository for the specified schemas.
Return the SQL parameter placeholder string for a variable at a given index.
Quotes an identifier (column name, table name) using source-specific syntax.
Resolves which schema contains a table given a list of schemas to search.
Functions
Applies filters to a query using the source-specific implementation.
Applies sorts to a query using the source-specific implementation.
Returns the list of built-in deny rules for system tables and metadata relations.
Returns the list of built-in schema denies that should be hidden from schema listing.
Returns the default schemas for the given repository's source.
Executes a function within a transaction with source-specific session management.
Retrieves the execution plan for a SQL query.
Formats a database error into a consistent, human-readable string.
Gets the schema information for a specific table.
Returns the source-specific SQL parameter placeholders for LIMIT and OFFSET clauses.
Lists all schemas in the given repository.
Lists all tables in the given repository for the specified schemas.
Returns the source-specific SQL parameter placeholder to substitute
for {{var}} occurrences.
Quotes an identifier (column name, table name) using source-specific syntax.
Resolves which schema contains a table given a list of schemas to search.
Sets the search path (schema list) for the given repository, if supported by the underlying source.
Sets the statement timeout (in milliseconds) for the given repository, if supported by the underlying source.
Types
@type repo() :: Ecto.Repo.t()
Callbacks
@callback apply_filters(sql :: String.t(), filters :: [Lotus.Query.Filter.t()]) :: String.t()
Applies a list of filters to an existing query, returning a new query string.
For SQL sources, this typically wraps the original query in a CTE and appends WHERE clauses. Non-SQL sources may implement entirely different strategies.
Returns the original query unchanged when filters is empty.
@callback apply_sorts(sql :: String.t(), sorts :: [Lotus.Query.Sort.t()]) :: String.t()
Applies a list of sorts to an existing query, returning a new query string.
For SQL sources, this appends an ORDER BY clause. Applied after filters so the ORDER BY operates on the filtered result set.
Returns the original query unchanged when sorts is empty.
Return the list of built-in deny rules for system tables and metadata relations that should be hidden from the schema browser for this source.
Each rule is a {schema_pattern, table_pattern} tuple where patterns can be
exact strings or regexes. Example rules:
{"pg_catalog", ~r/.*/}→ deny all tables in Postgrespg_catalog{nil, ~r/^sqlite_/}→ deny all tables starting withsqlite_in SQLite{"public", "schema_migrations"}→ deny migrations table in Postgres
Return the list of built-in schema denies that should be hidden from schema listing.
Returns a list of schema patterns (strings or regexes) that should be denied.
Examples:
- PostgreSQL:
["pg_catalog", "information_schema", ~r/^pg_temp/] - MySQL:
["mysql", "information_schema", "performance_schema", "sys"] - SQLite:
[](no schemas)
Return the default schemas for this source when no schema options are provided.
Each database source defines its own appropriate default:
- PostgreSQL →
["public"] - MySQL →
[database_name](uses database name as schema) - SQLite →
[](schema-less)
@callback explain_plan(repo(), sql :: String.t(), params :: list(), opts :: keyword()) :: {:ok, String.t()} | {:error, term()}
Retrieve the execution plan for a SQL query.
Uses the database-specific EXPLAIN syntax to return the query plan as a string suitable for analysis.
Examples of source-specific behavior:
- Postgres →
EXPLAIN (FORMAT JSON) <sql> - MySQL →
EXPLAIN FORMAT=JSON <sql> - SQLite →
EXPLAIN QUERY PLAN <sql>
Options:
:search_path— PostgreSQL search path (optional)
@callback get_table_schema(repo(), schema :: String.t() | nil, table :: String.t()) :: [ %{ name: String.t(), type: String.t(), nullable: boolean(), default: String.t() | nil, primary_key: boolean() } ]
Gets the schema information for a specific table.
Returns a list of column definitions. Each column is a map with exactly these keys:
:name- Column name (String.t()):type- SQL type as string (e.g., "varchar(255)", "integer", "text"):nullable- Whether column allows NULL (boolean):default- Default value as string or nil:primary_key- Whether column is part of primary key (boolean)
Example return value
[
%{
name: "id",
type: "integer",
nullable: false,
default: nil,
primary_key: true
},
%{
name: "email",
type: "varchar(255)",
nullable: false,
default: nil,
primary_key: false
}
]
@callback handled_errors() :: [module()]
List the exception modules that this source formats specially in format_error/1.
@callback limit_offset_placeholders( limit_index :: pos_integer(), offset_index :: pos_integer() ) :: {limit_placeholder :: String.t(), offset_placeholder :: String.t()}
Return the SQL parameter placeholders for LIMIT and OFFSET clauses.
Some databases (like MySQL) don't support typed placeholders for LIMIT/OFFSET, while others (like PostgreSQL) do.
Returns a tuple of {limit_placeholder, offset_placeholder}.
Examples:
- Postgres →
{"$1", "$2"} - MySQL →
{"?", "?"} - SQLite →
{"?", "?"}
Lists all schemas in the given repository.
Returns a list of schema names. For databases without schema support (like SQLite), returns an empty list.
Return format
- PostgreSQL/MySQL:
["public", "reporting", "analytics", ...] - SQLite:
[]
@callback list_tables(repo(), schemas :: [String.t()], include_views? :: boolean()) :: [ {schema :: String.t() | nil, table :: String.t()} ]
Lists all tables in the given repository for the specified schemas.
Returns a list of {schema, table} tuples. For databases without schema support (like SQLite), schema will always be nil.
Return format
- PostgreSQL/MySQL:
[{"public", "users"}, {"reporting", "orders"}, ...] - SQLite:
[{nil, "users"}, {nil, "orders"}, ...]
Options:
:include_views- Include views in results (default: false)
@callback param_placeholder( index :: pos_integer(), var :: String.t(), type :: atom() | nil ) :: String.t()
Return the SQL parameter placeholder string for a variable at a given index.
The placeholder may include database-specific type casting based on the variable type.
Examples of source-specific output:
- Postgres →
"$1"(untyped),"$1::integer"(typed) - MySQL →
"?"(untyped),"CAST(? AS SIGNED)"(typed) - SQLite →
"?"(always untyped)
Supported types for casting: :date, :datetime, :time, :number, :integer, :boolean, :json
Quotes an identifier (column name, table name) using source-specific syntax.
Examples:
- PostgreSQL →
"column_name" - MySQL →
`column_name` - SQLite →
"column_name"
@callback resolve_table_schema(repo(), table :: String.t(), schemas :: [String.t()]) :: String.t() | nil
Resolves which schema contains a table given a list of schemas to search.
Returns the schema name if found, nil otherwise. For databases without schema support (SQLite), this should always return nil.
The search should respect the order of schemas provided (first match wins).
@callback set_statement_timeout(repo(), non_neg_integer()) :: :ok | no_return()
Functions
@spec apply_filters(repo() | String.t() | nil, String.t(), [Lotus.Query.Filter.t()]) :: String.t()
Applies filters to a query using the source-specific implementation.
Returns the original query unchanged when filters is empty.
@spec apply_sorts(repo() | String.t() | nil, String.t(), [Lotus.Query.Sort.t()]) :: String.t()
Applies sorts to a query using the source-specific implementation.
Returns the original query unchanged when sorts is empty.
Returns the list of built-in deny rules for system tables and metadata relations.
These rules are used by the visibility module to filter out system tables.
Returns the list of built-in schema denies that should be hidden from schema listing.
These rules are used by the visibility module to filter out system schemas.
Returns the default schemas for the given repository's source.
Each database source defines its own appropriate default:
- PostgreSQL →
["public"] - MySQL →
[database_name](uses database name as schema) - SQLite →
[](schema-less)
Executes a function within a transaction with source-specific session management.
The source handles:
- Starting a transaction with appropriate timeout
- Setting read-only mode, statement timeout, and search path if specified in opts
- Running the provided function
- Properly cleaning up session state (important for MySQL/SQLite session persistence)
Options:
:read_only- whether to run in read-only mode (default: true):statement_timeout_ms- statement timeout in milliseconds (default: 5000):timeout- transaction timeout in milliseconds (default: 15000):search_path- PostgreSQL search path (optional)
Retrieves the execution plan for a SQL query.
Dispatches to the source-specific implementation based on the repo's adapter. Returns the plan as a string suitable for AI analysis.
Options:
:search_path- PostgreSQL search path (optional)
Formats a database error into a consistent, human-readable string.
Dispatches to the correct source if the error type is recognized, otherwise falls back to the default implementation.
@spec get_table_schema(repo(), String.t() | nil, String.t()) :: [ %{ name: String.t(), type: String.t(), nullable: boolean(), default: String.t() | nil, primary_key: boolean() } ]
Gets the schema information for a specific table.
Dispatches to the source-specific implementation based on the repo's adapter.
@spec limit_offset_placeholders( repo() | String.t() | nil, pos_integer(), pos_integer() ) :: {String.t(), String.t()}
Returns the source-specific SQL parameter placeholders for LIMIT and OFFSET clauses.
repo_or_namecan be the Repo module or a data-repo name string.limit_indexandoffset_indexare 1-based indexes for the parameters.
Falls back to the configured default data repo when nil is given.
Lists all schemas in the given repository.
Dispatches to the source-specific implementation based on the repo's adapter.
Lists all tables in the given repository for the specified schemas.
Dispatches to the source-specific implementation based on the repo's adapter.
@spec param_placeholder( repo() | String.t() | nil, pos_integer(), String.t(), atom() | nil ) :: String.t()
Returns the source-specific SQL parameter placeholder to substitute
for {{var}} occurrences.
repo_or_namecan be the Repo module or a data-repo name string.indexis 1-based (for drivers like Postgres that need$1,$2, …).varandtypeare available to sources if they need special handling.
Falls back to the configured default data repo when nil is given.
Quotes an identifier (column name, table name) using source-specific syntax.
Resolves which schema contains a table given a list of schemas to search.
Dispatches to the source-specific implementation based on the repo's adapter.
Sets the search path (schema list) for the given repository, if supported by the underlying source.
On unsupported sources this is a no-op.
@spec set_statement_timeout(repo(), non_neg_integer()) :: :ok | no_return()
Sets the statement timeout (in milliseconds) for the given repository, if supported by the underlying source.