ExSQL.Table (exsql v0.1.1)

Copy Markdown

In-memory table storage.

Rows live in a map keyed by rowid, mirroring SQLite's model where every table is a B-tree keyed by a 64-bit rowid. A single INTEGER PRIMARY KEY column is detected as the rowid alias, with SQLite's semantics: inserting NULL into it auto-assigns the next rowid, and the column's value is the row's key.

All functions are pure — they return an updated table or an error tuple. Constraint enforcement (NOT NULL, UNIQUE, PRIMARY KEY) happens here, by scanning; real indexes can replace the scans later without changing the interface.

Summary

Types

A CHECK constraint: {constraint_name | nil, expr}.

A composite PK or UNIQUE constraint: {constraint_name | nil, [column_key]}.

A table-level FK: {child_keys, parent_table, parent_keys, actions}, where actions is %{on_delete: action, on_update: action, deferred: boolean}.

t()

Functions

Returns the ColumnDef for name, or nil.

Deletes the rows with the given rowids.

Inserts a row given as a map of column key => value (already evaluated and affinity-coerced by the executor). Missing columns get their DEFAULT or NULL.

Case-insensitive column lookup key, since SQL identifiers fold case.

Creates a table from a name, parsed column definitions, and optional table-level constraints.

All rows in rowid order, as {rowid, row} pairs.

Replaces the row at rowid with row (a full row map), re-checking constraints. If the rowid-alias column changed, the row is re-keyed. Takes the same :on_conflict option as insert/3.

Types

check_constraint()

@type check_constraint() :: {String.t() | nil, term()}

A CHECK constraint: {constraint_name | nil, expr}.

composite_constraint()

@type composite_constraint() :: {String.t() | nil, [String.t()]}

A composite PK or UNIQUE constraint: {constraint_name | nil, [column_key]}.

foreign_key()

@type foreign_key() ::
  {[String.t()], String.t(), [String.t()], ExSQL.AST.CreateTable.fk_actions()}

A table-level FK: {child_keys, parent_table, parent_keys, actions}, where actions is %{on_delete: action, on_update: action, deferred: boolean}.

index()

@type index() :: %{name: String.t(), columns: [String.t()], unique: boolean()}

row()

@type row() :: %{required(String.t()) => ExSQL.Value.t()}

t()

@type t() :: %ExSQL.Table{
  autoincrement: boolean(),
  autoindexes: [index()],
  checks: [check_constraint()],
  columns: [ExSQL.AST.ColumnDef.t()],
  composite_keys: [composite_constraint()],
  composite_uniques: [composite_constraint()],
  foreign_keys: [foreign_key()],
  indexes: [index()],
  name: String.t(),
  next_rowid: pos_integer(),
  rowid_alias: String.t() | nil,
  rows: %{required(integer()) => row()},
  schema: String.t() | nil,
  sequence: integer(),
  sequence_row: boolean(),
  strict: boolean(),
  without_rowid: boolean()
}

Functions

column(table, name)

@spec column(t(), String.t()) :: ExSQL.AST.ColumnDef.t() | nil

Returns the ColumnDef for name, or nil.

delete_rows(table, rowids)

@spec delete_rows(t(), [integer()]) :: t()

Deletes the rows with the given rowids.

insert(table, values, opts \\ [])

@spec insert(t(), row(), keyword()) ::
  {:ok, t(), integer()} | :ignore | {:error, String.t()}

Inserts a row given as a map of column key => value (already evaluated and affinity-coerced by the executor). Missing columns get their DEFAULT or NULL.

Options:

  • :rowid — an explicit rowid (from inserting into rowid by name)
  • :on_conflict:abort (default) errors, :replace deletes the conflicting rows first, :ignore skips the insert and returns :ignore

key(name)

@spec key(String.t()) :: String.t()

Case-insensitive column lookup key, since SQL identifiers fold case.

new(name, columns, opts \\ [])

@spec new(String.t(), [ExSQL.AST.ColumnDef.t()], keyword()) :: t()

Creates a table from a name, parsed column definitions, and optional table-level constraints.

scan(table)

@spec scan(t()) :: [{integer(), row()}]

All rows in rowid order, as {rowid, row} pairs.

update_row(table, rowid, row, opts \\ [])

@spec update_row(t(), integer(), row(), keyword()) ::
  {:ok, t()} | :ignore | {:error, String.t()}

Replaces the row at rowid with row (a full row map), re-checking constraints. If the rowid-alias column changed, the row is re-keyed. Takes the same :on_conflict option as insert/3.