barrel (barrel v1.0.0)

View Source

Barrel: the embeddable edge database.

Composes the document layer (barrel_docdb) and the vector layer (barrel_vectordb) behind one API. A barrel database is a docdb database plus a vectordb store that share a name and a single id space: a document, its attachments (blobs), and its vector are all addressed by the same id. Blobs are docdb attachments; their storage backend is pluggable per database via the docdb barrel_att_backend seam.

open/2 returns a handle used by the rest of this module. Each underlying application stays usable on its own; barrel adds no storage of its own, it only coordinates the layers.

Summary

Types

Handle for a composed barrel database. Treat it as opaque: names are binaries internally (atoms are accepted at every API entry and normalized, so dynamic database names never grow the atom table). The optional embedding, embed, and dimensions fields are present on record-mode databases (opened with the embedding option): the validated policy, barrel's barrel_embed state, and the resolved vector dimension. encryption carries the spec the database was opened with (branches inherit it).

Opaque attachment read/write stream handle.

Functions

Abort an attachment writer.

Get attachment metadata (content type, length, digest).

Fork a composed database into a branch (timeline). The docdb forks instantly (at now, or rewound to a past HLC with at => HlcT); the branch opens as its own composed database with a FRESH vector store. Plain databases do not carry vectors across the fork in v1 (they live only in the vector store; re-add or reindex on the branch). Record-mode branches backfill from the embeddings stored in doc bodies, see barrel_record_backfill.

Get changes since an HLC timestamp (first for all).

Get changes since an HLC timestamp, with options.

Close a composed barrel database (indexer, then vector store, then document database).

Close an attachment reader.

Delete a composed barrel database: stop the indexer, destroy the vector store (handles closed, directory removed), and delete the document database's files.

Delete a document attachment.

Delete a document by id. On record-mode databases the delete is tagged so the indexer removes the document's vector; in sync mode the vector is removed before returning.

Delete a document by id with options (e.g. provenance).

Delete multiple documents by id. docdb has no bulk delete, so this maps over delete_doc/2 and returns a result per id, in order.

Every retained version of a document: the current winner (with last-writer provenance when recorded) followed by live conflict siblings and superseded versions.

Explain a BQL query: source, streamability, warnings, and the engine's index strategy for collection queries.

Run a declarative query.

Run a declarative query with options.

Finalise an attachment writer.

Fetch a document attachment.

Get a document by id.

Get a document by id with options.

Get multiple documents by id in one batch. Returns a result per input id, in order.

Get multiple documents by id in one batch, with options.

The retained history log, oldest first: one entry per applied write within the retention window (see barrel_history). Entries carry hlc, id, version, deleted, cause, vv, and provenance when the write recorded it.

Like history/1 with options: from/to (HLC bounds), limit (bounds the SCAN, not the matches), and id (keep only one document's entries; applied while scanning, so combined with limit fewer than limit entries can return).

The oldest HLC the history is complete from (undefined until a retention sweep runs).

Decode a cursor produced by hlc_encode/1 back to an HLC timestamp usable as the Since argument of changes/2.

Encode an HLC timestamp (the cursor returned by changes/2) as a JSON/URL-safe string, for transports that serialise the changes feed.

Database metadata.

List a document's attachment names.

Merge a branch's edits back into its parent (see barrel_docdb:merge_branch/2). When the parent is a record-mode database open in this VM, its indexer is nudged so merged docs embed promptly (the outbox entries exist either way).

Open a composed barrel database with default options.

Open a composed barrel database.

Open a streaming reader for an attachment.

Open a streaming writer for an attachment.

Store a document attachment.

Create or update a document. On record-mode databases the write is tagged for async vector indexing (same signature, policy applied transparently).

Create or update a document with options. On record-mode databases: vector => Vector supplies an explicit embedding (skips the embedder, indexed synchronously); a policy in sync mode embeds before returning (read-your-write search). Both fail the put on embed/dimension errors BEFORE writing; failures after the document committed are healed by the indexer.

Create or update multiple documents in one batch. Returns a result per input document, in order.

Create or update multiple documents in one batch, with options. On a sync-mode record database the batch embeds (embed_batch) before writing and indexes before returning; an embed failure fails the whole batch with nothing written.

Run a BQL query (see barrel_bql). Unlike barrel_docdb:query/2, table-function sources (vector_top_k, bm25_top_k, hybrid_top_k) execute here, joined back to their documents. SUBSCRIBE queries need subscribe_query (live queries).

Run a BQL query with options: params (a map for $name placeholders), chunk_size / continuation (streamable queries), and overfetch (table functions, default 3).

Fold BQL rows without materializing the full result. Fun(Row, Acc) -> {ok, Acc} | {stop, Acc}.

Read the next chunk from an attachment reader.

Semantic search over the vector store.

BM25 keyword search.

Hybrid (vector + BM25) search. On record-mode databases barrel embeds the query itself and passes it as query_vector (the store has no embedder).

Vector search with an explicit query vector.

Subscribe to a changes stream from Since. Returns a stream pid.

Subscribe to a changes stream with options.

Acknowledge a push-mode batch (drives backpressure).

Start a live query for a BQL SUBSCRIBE statement. The initial snapshot and add/change/remove deltas are pushed to the owner process (default: the caller); see barrel_bql_live for the message shapes. Returns an opaque subscription for unsubscribe_query/1; monitor its pid for crash signals. Owner death tears the query down.

Like subscribe_query/2 with options: params, owner.

Stop a changes stream started with subscribe/2,3.

Stop a live query. Idempotent.

Add a document to the vector store (text embedded by the store).

Add a document to the vector store with an explicit vector.

Add many documents to the vector store in one atomic batch.

Delete a vector entry by id.

Get a stored vector entry by id.

Vector store statistics.

The body of one version of a document (current or archived; swept bodies are gone).

Write a chunk to an attachment writer.

Types

db/0

-type db() ::
          #{name := binary(),
            docdb := binary(),
            vstore := binary(),
            embedding => barrel_embedding_policy:policy(),
            embed => term(),
            dimensions => pos_integer(),
            encryption => barrel_keyprovider:spec()}.

Handle for a composed barrel database. Treat it as opaque: names are binaries internally (atoms are accepted at every API entry and normalized, so dynamic database names never grow the atom table). The optional embedding, embed, and dimensions fields are present on record-mode databases (opened with the embedding option): the validated policy, barrel's barrel_embed state, and the resolved vector dimension. encryption carries the spec the database was opened with (branches inherit it).

db_name/0

-type db_name() :: atom() | binary().

stream/0

-type stream() :: term().

Opaque attachment read/write stream handle.

Functions

abort_attachment(Writer)

-spec abort_attachment(stream()) -> ok.

Abort an attachment writer.

attachment_info(_, DocId, AttName)

-spec attachment_info(db(), binary(), binary()) -> {ok, map()} | {error, term()}.

Get attachment metadata (content type, length, digest).

branch(Db, BranchName)

-spec branch(db(), db_name()) -> {ok, db()} | {error, term()}.

Fork a composed database into a branch (timeline). The docdb forks instantly (at now, or rewound to a past HLC with at => HlcT); the branch opens as its own composed database with a FRESH vector store. Plain databases do not carry vectors across the fork in v1 (they live only in the vector store; re-add or reindex on the branch). Record-mode branches backfill from the embeddings stored in doc bodies, see barrel_record_backfill.

Opts: at (now | HlcT), docdb (branch docdb overrides), vectordb (branch vector store config, e.g. db_path), backfill (record mode: sync | none).

branch(Db, BranchName, Opts)

-spec branch(db(), db_name(), map()) -> {ok, db()} | {error, term()}.

changes(_, Since)

-spec changes(db(), term()) -> {ok, [map()], term()}.

Get changes since an HLC timestamp (first for all).

changes(_, Since, Opts)

-spec changes(db(), term(), map()) -> {ok, [map()], term()}.

Get changes since an HLC timestamp, with options.

close(Db)

-spec close(db()) -> ok | {error, term()}.

Close a composed barrel database (indexer, then vector store, then document database).

close_attachment_reader(Stream)

-spec close_attachment_reader(stream()) -> ok.

Close an attachment reader.

delete(Db)

-spec delete(db()) -> ok | {error, term()}.

Delete a composed barrel database: stop the indexer, destroy the vector store (handles closed, directory removed), and delete the document database's files.

delete_attachment(_, DocId, AttName)

-spec delete_attachment(db(), binary(), binary()) -> ok | {error, term()}.

Delete a document attachment.

delete_doc(Db, DocId)

-spec delete_doc(db(), binary()) -> {ok, map()} | {error, term()}.

Delete a document by id. On record-mode databases the delete is tagged so the indexer removes the document's vector; in sync mode the vector is removed before returning.

delete_doc(Db, DocId, Opts)

-spec delete_doc(db(), binary(), map()) -> {ok, map()} | {error, term()}.

Delete a document by id with options (e.g. provenance).

delete_docs(Db, DocIds)

-spec delete_docs(db(), [binary()]) -> [{ok, map()} | {error, term()}].

Delete multiple documents by id. docdb has no bulk delete, so this maps over delete_doc/2 and returns a result per id, in order.

doc_versions(_, DocId)

-spec doc_versions(db(), binary()) -> {ok, [map()]} | {error, term()}.

Every retained version of a document: the current winner (with last-writer provenance when recorded) followed by live conflict siblings and superseded versions.

explain_query(Db, Bql)

-spec explain_query(db(), binary() | string()) -> {ok, map()} | {error, term()}.

Explain a BQL query: source, streamability, warnings, and the engine's index strategy for collection queries.

explain_query(Db, Bql, Opts)

-spec explain_query(db(), binary() | string(), map()) -> {ok, map()} | {error, term()}.

find(_, Query)

-spec find(db(), map()) -> {ok, [map()], map()} | {error, term()}.

Run a declarative query.

find(_, Query, Opts)

-spec find(db(), map(), map()) -> {ok, [map()], map()} | {error, term()}.

Run a declarative query with options.

finish_attachment(Writer)

-spec finish_attachment(stream()) -> {ok, map()} | {error, term()}.

Finalise an attachment writer.

get_attachment(_, DocId, AttName)

-spec get_attachment(db(), binary(), binary()) -> {ok, binary()} | {error, term()}.

Fetch a document attachment.

get_doc(_, DocId)

-spec get_doc(db(), binary()) -> {ok, map()} | {error, term()}.

Get a document by id.

get_doc(_, DocId, Opts)

-spec get_doc(db(), binary(), map()) -> {ok, map()} | {ok, binary(), map()} | {error, term()}.

Get a document by id with options.

get_docs(_, DocIds)

-spec get_docs(db(), [binary()]) -> [{ok, map()} | {error, term()}] | {error, term()}.

Get multiple documents by id in one batch. Returns a result per input id, in order.

get_docs(_, DocIds, Opts)

-spec get_docs(db(), [binary()], map()) -> [{ok, map()} | {error, term()}] | {error, term()}.

Get multiple documents by id in one batch, with options.

history(Db)

-spec history(db()) -> {ok, [barrel_history:entry()]} | {error, term()}.

The retained history log, oldest first: one entry per applied write within the retention window (see barrel_history). Entries carry hlc, id, version, deleted, cause, vv, and provenance when the write recorded it.

history(_, Opts)

-spec history(db(), map()) -> {ok, [barrel_history:entry()]} | {error, term()}.

Like history/1 with options: from/to (HLC bounds), limit (bounds the SCAN, not the matches), and id (keep only one document's entries; applied while scanning, so combined with limit fewer than limit entries can return).

history_floor(_)

-spec history_floor(db()) -> barrel_hlc:timestamp() | undefined.

The oldest HLC the history is complete from (undefined until a retention sweep runs).

hlc_decode(Cursor)

-spec hlc_decode(binary()) -> term().

Decode a cursor produced by hlc_encode/1 back to an HLC timestamp usable as the Since argument of changes/2.

hlc_encode(Hlc)

-spec hlc_encode(term()) -> binary().

Encode an HLC timestamp (the cursor returned by changes/2) as a JSON/URL-safe string, for transports that serialise the changes feed.

info(Db)

-spec info(db()) -> {ok, map()} | {error, term()}.

Database metadata.

list_attachments(_, DocId)

-spec list_attachments(db(), binary()) -> [binary()].

List a document's attachment names.

merge(Db)

-spec merge(db()) -> {ok, map()} | {error, term()}.

Merge a branch's edits back into its parent (see barrel_docdb:merge_branch/2). When the parent is a record-mode database open in this VM, its indexer is nudged so merged docs embed promptly (the outbox entries exist either way).

merge(_, Opts)

-spec merge(db(), map()) -> {ok, map()} | {error, term()}.

open(Name)

-spec open(db_name()) -> {ok, db()} | {error, term()}.

Open a composed barrel database with default options.

open(Name, Opts)

-spec open(db_name(), map()) -> {ok, db()} | {error, term()}.

Open a composed barrel database.

Opts may carry docdb => map() (passed to barrel_docdb:create_db/2, including att_opts to choose an attachment backend) and vectordb => map() (a barrel_vectordb store config; its name is set from Name). Opens the docdb database if it exists, otherwise creates it, then starts the vectordb store.

embedding => PolicyMap opens the database in RECORD MODE: writes are tagged for asynchronous vector indexing driven by the database's embedding policy (see barrel_embedding_policy), the vector store keeps only vectors and indexes (text/metadata read through the record's documents), and BM25 defaults to the disk backend so it survives restarts. Without the option, behavior is unchanged.

encryption => disabled | default | #{provider => Mod} encrypts the WHOLE logical database at rest under one key: the docdb stores take it as-is, and barrel resolves the key once (on the docdb keyspace, so a branch resolves its parent's key) and hands it to the vector store. Runtime config: pass it again on every open. Branches inherit the spec from the parent handle.

open_attachment_reader(_, DocId, AttName)

-spec open_attachment_reader(db(), binary(), binary()) -> {ok, stream()} | {error, term()}.

Open a streaming reader for an attachment.

open_attachment_writer(_, DocId, AttName, ContentType)

-spec open_attachment_writer(db(), binary(), binary(), binary()) -> {ok, stream()} | {error, term()}.

Open a streaming writer for an attachment.

put_attachment(_, DocId, AttName, Data)

-spec put_attachment(db(), binary(), binary(), binary()) -> {ok, map()} | {error, term()}.

Store a document attachment.

put_doc(Db, Doc)

-spec put_doc(db(), map()) -> {ok, map()} | {error, term()}.

Create or update a document. On record-mode databases the write is tagged for async vector indexing (same signature, policy applied transparently).

put_doc(Db, Doc, Opts)

-spec put_doc(db(), map(), map()) -> {ok, map()} | {error, term()}.

Create or update a document with options. On record-mode databases: vector => Vector supplies an explicit embedding (skips the embedder, indexed synchronously); a policy in sync mode embeds before returning (read-your-write search). Both fail the put on embed/dimension errors BEFORE writing; failures after the document committed are healed by the indexer.

put_docs(Db, Docs)

-spec put_docs(db(), [map()]) -> [{ok, map()} | {error, term()}].

Create or update multiple documents in one batch. Returns a result per input document, in order.

put_docs(Db, Docs, Opts)

-spec put_docs(db(), [map()], map()) -> [{ok, map()} | {error, term()}] | {error, term()}.

Create or update multiple documents in one batch, with options. On a sync-mode record database the batch embeds (embed_batch) before writing and indexes before returning; an embed failure fails the whole batch with nothing written.

query(Db, Bql)

-spec query(db(), binary() | string()) -> {ok, [map()], map()} | {error, term()}.

Run a BQL query (see barrel_bql). Unlike barrel_docdb:query/2, table-function sources (vector_top_k, bm25_top_k, hybrid_top_k) execute here, joined back to their documents. SUBSCRIBE queries need subscribe_query (live queries).

query(Db, Bql, Opts)

-spec query(db(), binary() | string(), map()) -> {ok, [map()], map()} | {error, term()}.

Run a BQL query with options: params (a map for $name placeholders), chunk_size / continuation (streamable queries), and overfetch (table functions, default 3).

query_fold(Db, Bql, Opts, Fun, Acc)

-spec query_fold(db(),
                 binary() | string(),
                 map(),
                 fun((map(), term()) -> {ok, term()} | {stop, term()}),
                 term()) ->
                    {ok, term(), map()} | {error, term()}.

Fold BQL rows without materializing the full result. Fun(Row, Acc) -> {ok, Acc} | {stop, Acc}.

read_attachment(Stream)

-spec read_attachment(stream()) -> {ok, binary(), stream()} | eof | {error, term()}.

Read the next chunk from an attachment reader.

search(_, Query, Opts)

-spec search(db(), binary(), map()) -> term().

Semantic search over the vector store.

search_bm25(_, Query, Opts)

-spec search_bm25(db(), binary(), map()) -> term().

BM25 keyword search.

search_hybrid(_, Query, Opts)

-spec search_hybrid(db(), binary(), map()) -> term().

Hybrid (vector + BM25) search. On record-mode databases barrel embeds the query itself and passes it as query_vector (the store has no embedder).

search_vector(_, Vector, Opts)

-spec search_vector(db(), [float()], map()) -> term().

Vector search with an explicit query vector.

subscribe(_, Since)

-spec subscribe(db(), term()) -> {ok, pid()} | {error, term()}.

Subscribe to a changes stream from Since. Returns a stream pid.

subscribe(_, Since, Opts)

-spec subscribe(db(), term(), map()) -> {ok, pid()} | {error, term()}.

Subscribe to a changes stream with options.

subscribe_ack(Stream, ReqId)

-spec subscribe_ack(pid(), reference()) -> ok.

Acknowledge a push-mode batch (drives backpressure).

subscribe_query(Db, Bql)

-spec subscribe_query(db(), binary() | string()) ->
                         {ok, #{ref := reference(), pid := pid()}} | {error, term()}.

Start a live query for a BQL SUBSCRIBE statement. The initial snapshot and add/change/remove deltas are pushed to the owner process (default: the caller); see barrel_bql_live for the message shapes. Returns an opaque subscription for unsubscribe_query/1; monitor its pid for crash signals. Owner death tears the query down.

subscribe_query(Db, Bql, Opts)

-spec subscribe_query(db(), binary() | string(), map()) ->
                         {ok, #{ref := reference(), pid := pid()}} | {error, term()}.

Like subscribe_query/2 with options: params, owner.

subscribe_stop(Stream)

-spec subscribe_stop(pid()) -> ok.

Stop a changes stream started with subscribe/2,3.

unsubscribe_query(_)

-spec unsubscribe_query(#{ref := reference(), pid := pid()}) -> ok.

Stop a live query. Idempotent.

vector_add(_, Id, Text, Metadata)

-spec vector_add(db(), binary(), binary(), map()) -> term().

Add a document to the vector store (text embedded by the store).

vector_add(_, Id, Text, Metadata, Vector)

-spec vector_add(db(), binary(), binary(), map(), [float()]) -> term().

Add a document to the vector store with an explicit vector.

vector_add_batch(_, Docs)

-spec vector_add_batch(db(), [tuple()]) -> {ok, map()} | {error, term()}.

Add many documents to the vector store in one atomic batch.

Each element is either {Id, Text, Metadata} (text embedded by the store) or {Id, Text, Metadata, Vector} (explicit vector). All elements must be the same shape; a mixed batch returns {error, mixed_batch}.

vector_delete(_, Id)

-spec vector_delete(db(), binary()) -> term().

Delete a vector entry by id.

vector_get(_, Id)

-spec vector_get(db(), binary()) -> term().

Get a stored vector entry by id.

vector_stats(_)

-spec vector_stats(db()) -> term().

Vector store statistics.

version_body(_, DocId, VersionToken)

-spec version_body(db(), binary(), binary()) -> {ok, map()} | {error, not_found}.

The body of one version of a document (current or archived; swept bodies are gone).

write_attachment(Writer, Data)

-spec write_attachment(stream(), binary()) -> {ok, stream()} | {error, term()}.

Write a chunk to an attachment writer.