Roux.Database (roux v0.2.2)

Copy Markdown View Source

Central handle for all framework state.

A database is a struct holding references to ETS tables, atomics counters, and the supervisor that owns those tables. It is the db parameter threaded through all query calls.

ETS tables survive TableOwner crashes transparently — table IDs are stable across ownership transfers, so existing Database structs remain valid. See Roux.Database.Heir for the crash recovery protocol.

Lifecycle

db = Roux.Database.new()
# ... register queries, inputs, entities ...
# ... execute queries ...
Roux.Database.shutdown(db)

Summary

Types

What tells a database apart from the others in the VM; see id/1.

t()

Functions

The code version a query is registered with (register_query/3): nil for a query registered without one, or not registered at all.

Looks up a query by name in the registry and invokes it with the given key.

Returns all registered entity type modules.

What tells this database apart from the others in the VM: its memo table, which no other database shares and which a Roux.Database.TableOwner restart keeps (see Roux.Database.Heir). Telemetry events carry it as database: metadata (Roux.Telemetry).

The durability an input was registered with (register_input/3), :medium when it names none. Raises ArgumentError for an input that is not registered.

Gets or creates an intern table by name.

Returns the names of all intern tables that have been created.

Creates a new database with all ETS tables and atomics initialized.

What a query is registered with (register_query/3), or nil.

Whether a derived query of this name is registered.

Registers an entity type, creating its ETS table for field storage.

Registers an input definition with its options.

Registers a derived query definition: at least its :module and :function, and optionally its :code_version, :store and :transient (Roux.Query).

Returns the revision tracker for this database.

Destroys all ETS tables and stops the supervisor.

How many entries this database's queries have written so far (note_write/1): a session compares it to tell whether a run computed anything its manifest does not hold.

Types

id()

@type id() :: :ets.tid()

What tells a database apart from the others in the VM; see id/1.

t()

@type t() :: %Roux.Database{
  blob: Roux.Blob.t() | nil,
  dedup_table: :ets.tid(),
  dedup_waiters: :ets.tid(),
  entity_registry: :ets.tid(),
  input_registry: :ets.tid(),
  intern_registry: :ets.tid(),
  memo_table: :ets.tid(),
  query_registry: :ets.tid(),
  revision: Roux.Revision.t(),
  supervisor: pid(),
  table_owner: pid(),
  task_registry: :ets.tid(),
  writes: :atomics.atomics_ref() | nil
}

Functions

code_version(database, name)

@spec code_version(t(), atom()) :: binary() | nil

The code version a query is registered with (register_query/3): nil for a query registered without one, or not registered at all.

dispatch_query(db, query_name, key)

@spec dispatch_query(t(), atom(), term()) :: term()

Looks up a query by name in the registry and invokes it with the given key.

Raises ArgumentError if the query is not registered.

entity_types(database)

@spec entity_types(t()) :: [module()]

Returns all registered entity type modules.

id(database)

@spec id(t()) :: id()

What tells this database apart from the others in the VM: its memo table, which no other database shares and which a Roux.Database.TableOwner restart keeps (see Roux.Database.Heir). Telemetry events carry it as database: metadata (Roux.Telemetry).

input_durability(database, name)

@spec input_durability(t(), atom()) :: Roux.Revision.durability()

The durability an input was registered with (register_input/3), :medium when it names none. Raises ArgumentError for an input that is not registered.

intern_table(database, name)

@spec intern_table(t(), atom()) :: Roux.Intern.t()

Gets or creates an intern table by name.

Lazily created on first access. Thread-safe via ETS CAS — concurrent calls with the same name return the same Roux.Intern.t().

intern_table_names(database)

@spec intern_table_names(t()) :: [atom()]

Returns the names of all intern tables that have been created.

new(opts \\ [])

@spec new(keyword()) :: t()

Creates a new database with all ETS tables and atomics initialized.

Starts a supervisor that owns all ETS tables via the Heir/TableOwner protocol. The returned struct holds stable references to those tables.

Options

  • :blob — a Roux.Blob store: where a manifest keeps the values of store: :blob queries and the database reads them back, and where code versions are kept across VMs (Roux.Query).

query_definition(database, name)

@spec query_definition(t(), atom()) :: map() | nil

What a query is registered with (register_query/3), or nil.

query_registered?(database, name)

@spec query_registered?(t(), atom()) :: boolean()

Whether a derived query of this name is registered.

register_entity(database, module)

@spec register_entity(t(), module()) :: :ok

Registers an entity type, creating its ETS table for field storage.

Idempotent — calling with the same module twice returns :ok without creating a second table.

register_input(database, name, opts \\ [])

@spec register_input(t(), atom(), keyword()) :: :ok

Registers an input definition with its options.

Options typically include :durability (defaults to :low).

register_query(database, name, definition)

@spec register_query(t(), atom(), map()) :: :ok

Registers a derived query definition: at least its :module and :function, and optionally its :code_version, :store and :transient (Roux.Query).

Idempotent — re-registering the same name overwrites the previous definition. Registering a query again under another code version makes every entry of the query stale, and advances the revision at :high so that no durability check skips the entries that read them.

revision(database)

@spec revision(t()) :: Roux.Revision.t()

Returns the revision tracker for this database.

shutdown(database)

@spec shutdown(t()) :: :ok

Destroys all ETS tables and stops the supervisor.

The database handle becomes invalid after this call.

writes(database)

@spec writes(t()) :: non_neg_integer()

How many entries this database's queries have written so far (note_write/1): a session compares it to tell whether a run computed anything its manifest does not hold.