ExSQL. Database
(exsql v0.1.5)
Copy Markdown
An immutable in-memory database: a schema of named tables.
This plays the role of SQLite's connection + pager state, except every
operation returns a new database value. Use it directly for a purely
functional workflow, or hold it in an ExSQL.Connection process for a
stateful, sqlite3-like handle.
{:ok, _, db} = ExSQL.Executor.run(ExSQL.Database.new(), "CREATE TABLE t (a)")
Summary
Types
A connection-local aggregate callback. It receives a list of evaluated,
non-NULL argument rows and must return a SQL value, {:ok, value}, or
{:error, message}. Incremental window callbacks use the same registry but
store a callback map and kind: :incremental_window.
A connection-local collation callback. It receives two TEXT values and
returns :lt/:eq/:gt, a negative/zero/positive integer, or
{:ok, result} / {:error, message}.
A materialized CTE result, threaded through query execution.
A connection-local scalar function callback. It receives evaluated SQL values
and must return a SQL value, {:ok, value}, or {:error, message}.
A stored trigger: parsed definition plus a creation sequence number that fixes firing order.
Open transactions and savepoints, newest first. Each entry snapshots both tables and views as they were when it was opened — rollback restores both.
A stored view: the parsed query and an optional explicit column list.
Functions
Returns true if any arity is registered for this aggregate function name.
Registers or replaces a connection-local aggregate function.
Registers or replaces a connection-local collation.
Registers or replaces a connection-local incremental aggregate window function.
Registers or replaces a connection-local scalar function.
Adds a new table; errors if the name collides with a table or existing view.
Adds a new view; errors if the name collides with a table or existing view.
Registers or replaces a connection-local aggregate window function.
Removes attached schema header state.
Removes a table; errors if it does not exist or if the name is a view.
Removes a view; errors if it does not exist or if the name is a table.
Fetches a registered aggregate function by name and exact SQL arity.
Fetches a registered collation by name.
Fetches a registered scalar function by name and exact arity.
Fetches a table by name (case-insensitive).
Fetches a view by name (case-insensitive).
Finds which table owns the index with the given name, or nil. Index lookup is database-global and case-insensitive.
Finds which table owns the index with the given name within a schema, or nil.
Returns true if any table has an index with this name.
Returns true if a table in the schema has an index with this name.
Fetches a table by unqualified name using SQLite's schema lookup order.
Fetches a view by unqualified name using SQLite's schema lookup order.
Returns an empty database.
Stores a schema header value for main or an attached schema.
Replaces a table's state after DML.
Records the row-count state exposed by changes() and total_changes().
Restores schema from a snapshot.
Returns true if any arity is registered for this scalar function name.
Bumps the schema cookie using SQLite's signed 32-bit wraparound.
Returns a schema header value for main or an attached schema.
Returns a snapshot of mutable schema state (tables, views, triggers) for transactions.
Internal storage key for schema-qualified tables.
Types
@type aggregate_function() :: %{ :name => String.t(), :arity => non_neg_integer(), :callback => function() | map(), optional(:kind) => :frame | :incremental_window }
A connection-local aggregate callback. It receives a list of evaluated,
non-NULL argument rows and must return a SQL value, {:ok, value}, or
{:error, message}. Incremental window callbacks use the same registry but
store a callback map and kind: :incremental_window.
A connection-local collation callback. It receives two TEXT values and
returns :lt/:eq/:gt, a negative/zero/positive integer, or
{:ok, result} / {:error, message}.
A materialized CTE result, threaded through query execution.
@type scalar_function() :: %{ name: String.t(), arity: non_neg_integer(), callback: function() }
A connection-local scalar function callback. It receives evaluated SQL values
and must return a SQL value, {:ok, value}, or {:error, message}.
@type t() :: %ExSQL.Database{ active_triggers: [String.t()], aggregate_functions: %{ required({String.t(), non_neg_integer()}) => aggregate_function() }, analysis_limit: non_neg_integer(), application_id: integer(), attached_databases: [ %{seq: pos_integer(), name: String.t(), file: String.t()} ], auto_vacuum: 0..2, automatic_index: boolean(), busy_timeout: non_neg_integer(), cache_size: integer(), cache_spill: non_neg_integer(), case_sensitive_like: boolean(), cell_size_check: boolean(), changes: non_neg_integer(), checkpoint_fullfsync: boolean(), collations: %{required(String.t()) => collation()}, count_changes: boolean(), ctes: %{required(String.t()) => cte()}, default_cache_size: non_neg_integer(), defer_foreign_keys: boolean(), empty_result_callbacks: boolean(), foreign_keys: boolean(), full_column_names: boolean(), fullfsync: boolean(), ignore_check_constraints: boolean(), journal_mode: String.t(), journal_size_limit: integer(), last_insert_rowid: integer(), locking_mode: String.t(), max_page_count: pos_integer(), page_size: pos_integer(), page_size_locked: boolean(), pending_ctes: term(), query_only: boolean(), read_uncommitted: boolean(), recursive_triggers: boolean(), reverse_unordered_selects: boolean(), scalar_functions: %{ required({String.t(), non_neg_integer()}) => scalar_function() }, schema_headers: %{required(String.t()) => map()}, schema_version: integer(), secure_delete: 0..2, short_column_names: boolean(), soft_heap_limit: non_neg_integer(), sqlite_sequence_orphans: map(), synchronous: 0..3, tables: %{required(String.t()) => ExSQL.Table.t()}, temp_store: 0..2, threads: 0..8, total_changes: non_neg_integer(), triggers: %{required(String.t()) => trigger()}, trusted_schema: boolean(), txn_stack: [txn_entry()], user_version: integer(), views: %{required(String.t()) => view()}, wal_autocheckpoint: non_neg_integer() }
@type trigger() :: %{ key: String.t(), name: String.t(), schema: String.t() | nil, table_schema: String.t() | nil, table_key: String.t(), timing: :before | :after | :instead_of, event: :insert | :delete | :update, update_columns: [String.t()] | nil, when: term() | nil, body: [term()], seq: non_neg_integer() }
A stored trigger: parsed definition plus a creation sequence number that fixes firing order.
@type txn_entry() :: {:begin | {:savepoint, String.t()}, %{ tables: %{required(String.t()) => ExSQL.Table.t()}, views: %{required(String.t()) => view()} }}
Open transactions and savepoints, newest first. Each entry snapshots both tables and views as they were when it was opened — rollback restores both.
@type view() :: %{ name: String.t(), schema: String.t() | nil, columns: [String.t()] | nil, query: term() }
A stored view: the parsed query and an optional explicit column list.
Functions
Returns true if any arity is registered for this aggregate function name.
@spec create_aggregate_function(t(), String.t(), non_neg_integer(), function()) :: {:ok, t()} | {:error, String.t()}
Registers or replaces a connection-local aggregate function.
The callback receives one list argument containing evaluated, non-NULL
argument rows. A one-argument SQL aggregate gets rows like [[value], ...];
a two-argument aggregate gets rows like [[a, b], ...].
Registers or replaces a connection-local collation.
The callback receives two TEXT values and returns :lt/:eq/:gt, a
negative/zero/positive integer, or {:ok, result} / {:error, message}.
@spec create_incremental_window_function(t(), String.t(), non_neg_integer(), map()) :: {:ok, t()} | {:error, String.t()}
Registers or replaces a connection-local incremental aggregate window function.
Callback map keys follow SQLite's aggregate window model: :init (arity 0),
:step and :inverse (arity 2, receiving state and evaluated SQL argument
list), and :value / :final (arity 1).
@spec create_scalar_function(t(), String.t(), non_neg_integer(), function()) :: {:ok, t()} | {:error, String.t()}
Registers or replaces a connection-local scalar function.
The callback arity must match the SQL arity exactly. The callback receives
evaluated SQL values as positional arguments and may return a SQL value,
{:ok, value}, or {:error, message}.
@spec create_table(t(), ExSQL.Table.t()) :: {:ok, t()} | {:error, String.t()}
Adds a new table; errors if the name collides with a table or existing view.
Adds a new view; errors if the name collides with a table or existing view.
@spec create_window_function(t(), String.t(), non_neg_integer(), function()) :: {:ok, t()} | {:error, String.t()}
Registers or replaces a connection-local aggregate window function.
The callback receives one list argument containing evaluated, non-NULL argument rows from the current window frame.
Removes attached schema header state.
Removes a table; errors if it does not exist or if the name is a view.
Removes a view; errors if it does not exist or if the name is a table.
@spec fetch_aggregate_function(t(), String.t(), non_neg_integer()) :: {:ok, aggregate_function()} | :error
Fetches a registered aggregate function by name and exact SQL arity.
Fetches a registered collation by name.
@spec fetch_scalar_function(t(), String.t(), non_neg_integer()) :: {:ok, scalar_function()} | :error
Fetches a registered scalar function by name and exact arity.
@spec fetch_table(t(), String.t()) :: {:ok, ExSQL.Table.t()} | {:error, String.t()}
Fetches a table by name (case-insensitive).
Fetches a view by name (case-insensitive).
@spec find_index_owner(t(), String.t()) :: {ExSQL.Table.t(), map()} | nil
Finds which table owns the index with the given name, or nil. Index lookup is database-global and case-insensitive.
@spec find_index_owner(t(), String.t() | nil, String.t()) :: {ExSQL.Table.t(), map()} | nil
Finds which table owns the index with the given name within a schema, or nil.
Returns true if any table has an index with this name.
Returns true if a table in the schema has an index with this name.
@spec lookup_table(t(), String.t()) :: {:ok, ExSQL.Table.t()} | {:error, String.t()}
Fetches a table by unqualified name using SQLite's schema lookup order.
Fetches a view by unqualified name using SQLite's schema lookup order.
@spec new() :: t()
Returns an empty database.
@spec put_schema_header_value( t(), String.t() | nil, :schema_version | :user_version | :application_id, integer() ) :: t()
Stores a schema header value for main or an attached schema.
@spec put_table(t(), ExSQL.Table.t()) :: t()
Replaces a table's state after DML.
@spec record_changes(t(), non_neg_integer()) :: t()
Records the row-count state exposed by changes() and total_changes().
@spec record_changes(t(), non_neg_integer(), integer() | nil) :: t()
Restores schema from a snapshot.
Returns true if any arity is registered for this scalar function name.
Bumps the schema cookie using SQLite's signed 32-bit wraparound.
@spec schema_header_value( t(), String.t() | nil, :schema_version | :user_version | :application_id ) :: integer()
Returns a schema header value for main or an attached schema.
@spec schema_snapshot(t()) :: %{ tables: map(), views: map(), triggers: map(), sqlite_sequence_orphans: map(), schema_version: integer(), user_version: integer(), application_id: integer(), schema_headers: map() }
Returns a snapshot of mutable schema state (tables, views, triggers) for transactions.
Internal storage key for schema-qualified tables.