Query builder that generates dllb SQL strings.
Provides functions to construct CREATE, SELECT, UPDATE, DELETE, RELATE, COUNT, DEFINE (secondary, full-text, and vector index), REMOVE INDEX, and SEARCH / VECTOR SEARCH statements for the dllb query language. All functions return plain query strings ready to be sent over the wire.
Summary
Functions
Builds a COUNT <table> [WHERE <clause>] statement.
Builds a CREATE statement for inserting a new record.
Builds a CREATE statement with an explicit record ID.
Builds a DEFINE FIELD statement.
Builds a DEFINE FULLTEXT INDEX statement that registers a BM25 full-text
(Tantivy) index over a single text field.
Builds a DEFINE INDEX statement that registers a persisted secondary
index in the engine's catalog and backfills entries for existing rows.
Builds a DEFINE TABLE statement.
Builds a DEFINE VECTOR INDEX statement that registers an approximate
nearest-neighbour (HNSW) index over a dense-embedding field.
Builds a DELETE statement for a record.
Builds a GRAPH COMMUNITIES statement for native community detection.
Builds a GRAPH COMPONENTS <edge_table> statement for native connected-
components detection.
Passes through a raw query string without modification.
Builds a RELATE statement to create a graph edge between two records.
Builds a REMOVE INDEX statement that drops a secondary index and all of
its catalog entries. Subsequent queries fall back to full scans.
Builds a SEARCH statement: a BM25 full-text query against a field that
has a full-text index. Results come back as rows ranked best-first, each
carrying an extra score field.
Builds a SELECT statement with optional clauses.
Builds an UPDATE statement for an existing record.
Builds an UPDATE <table> SET ... WHERE <clause> statement that updates
every row matching the (already-built) WHERE clause.
Builds a CREATE ... ON CONFLICT UPDATE statement for idempotent upserts.
Builds a VECTOR SEARCH statement: an approximate nearest-neighbour query
against a field that has a vector index. vector is the query embedding
(a list of numbers). Results come back as rows ordered nearest-first, each
carrying an extra distance field.
Types
Functions
Builds a COUNT <table> [WHERE <clause>] statement.
Options
:where- optional WHERE clause string
Examples
iex> Dllb.Query.count("user")
"COUNT user"
iex> Dllb.Query.count("user", where: "age = 30")
"COUNT user WHERE age = 30"
Builds a CREATE statement for inserting a new record.
Examples
iex> Dllb.Query.create("user", %{name: "Alice", age: 30})
"CREATE user SET age = 30, name = 'Alice'"
Builds a CREATE statement with an explicit record ID.
Examples
iex> Dllb.Query.create_with_id("user", "u1", %{name: "Alice"})
"CREATE user:u1 SET name = 'Alice'"
Builds a DEFINE FIELD statement.
Options
:required- iftrue, appends ASSERT $value IS NOT NONE
Examples
iex> Dllb.Query.define_field("user", "name", "string", required: true)
"DEFINE FIELD name ON user TYPE string ASSERT $value IS NOT NONE"
Builds a DEFINE FULLTEXT INDEX statement that registers a BM25 full-text
(Tantivy) index over a single text field.
Requires a dllb server with full-text/vector services enabled (the default server build).
Options
:analyzer- tokenizer/stemmer to apply. One of"default","simple", or a language ("english","spanish","french","german","italian","portuguese","russian"). Defaults to the engine'sdefaultanalyzer when omitted.
Examples
iex> Dllb.Query.define_fulltext_index("article", "ft_body", "body")
"DEFINE FULLTEXT INDEX ft_body ON TABLE article FIELDS body"
iex> Dllb.Query.define_fulltext_index("article", "ft_body", "body", analyzer: "english")
"DEFINE FULLTEXT INDEX ft_body ON TABLE article FIELDS body ANALYZER english"
Builds a DEFINE INDEX statement that registers a persisted secondary
index in the engine's catalog and backfills entries for existing rows.
The index covers one or more fields. Composite (multi-field) indexes are
matched by the engine using leftmost-prefix planning, so list the most
selective leading field first. Once defined, equality and range
(>, >=, <, <=) predicates on the indexed fields are transparently
accelerated in SELECT/COUNT/UPDATE WHERE clauses — no change to the
query strings is required.
Options
:unique- whentrue, enforces uniqueness over the full indexed tuple; defining the index fails if existing rows already hold duplicate values (defaultfalse)
Examples
iex> Dllb.Query.define_index("user", "by_age", ["age"])
"DEFINE INDEX by_age ON TABLE user FIELDS age"
iex> Dllb.Query.define_index("user", "by_email", ["email"], unique: true)
"DEFINE INDEX by_email ON TABLE user FIELDS email UNIQUE"
iex> Dllb.Query.define_index("ast_node", "idx_file_kind", ["file_path", "kind"])
"DEFINE INDEX idx_file_kind ON TABLE ast_node FIELDS file_path, kind"
Builds a DEFINE TABLE statement.
Mode can be :schemafull or :schemaless.
Examples
iex> Dllb.Query.define_table("user", :schemafull)
"DEFINE TABLE user SCHEMAFULL"
@spec define_vector_index( String.t(), String.t(), String.t(), pos_integer(), keyword() ) :: String.t()
Builds a DEFINE VECTOR INDEX statement that registers an approximate
nearest-neighbour (HNSW) index over a dense-embedding field.
dimension is the (positive) length of the vectors to be indexed. Requires
a dllb server with full-text/vector services enabled (the default server
build).
Options
:metric- distance metric:"cosine"(default),"euclidean"(alias"l2"), or"dot"(alias"dotproduct"/"dot_product"). Defaults to the engine'scosinemetric when omitted.
Examples
iex> Dllb.Query.define_vector_index("ast_node", "vec_src", "source_embedding", 768)
"DEFINE VECTOR INDEX vec_src ON TABLE ast_node FIELDS source_embedding DIMENSION 768"
iex> Dllb.Query.define_vector_index("doc", "vec_emb", "embedding", 8, metric: "euclidean")
"DEFINE VECTOR INDEX vec_emb ON TABLE doc FIELDS embedding DIMENSION 8 METRIC euclidean"
Builds a DELETE statement for a record.
Examples
iex> Dllb.Query.delete("user:u1")
"DELETE user:u1"
Builds a GRAPH COMMUNITIES statement for native community detection.
Delegates computation to the dllb engine (Rust Louvain / Label Propagation), which runs in O(E) per iteration — orders of magnitude faster than the equivalent pure-Elixir implementation on large graphs.
Options
:algorithm-:louvain(default) or:lp(label propagation):max_iter- maximum optimisation passes (default: 10):resolution- Louvain resolution γ; values < 1.0 → fewer, larger communities; > 1.0 → more, smaller communities (default: 1.0)
Examples
iex> Dllb.Query.graph_communities("calls")
"GRAPH COMMUNITIES calls"
iex> Dllb.Query.graph_communities("calls", algorithm: :lp, max_iter: 20)
"GRAPH COMMUNITIES calls ALGORITHM lp MAX_ITER 20"
iex> Dllb.Query.graph_communities("calls", algorithm: :louvain, resolution: 0.5)
"GRAPH COMMUNITIES calls ALGORITHM louvain RESOLUTION 0.5"
Builds a GRAPH COMPONENTS <edge_table> statement for native connected-
components detection.
Delegates computation to the dllb engine (Rust union-find over the edge
table, treated as undirected). The server returns a compact summary
(component_count, largest, nodes) rather than full membership.
Examples
iex> Dllb.Query.graph_components("calls")
"GRAPH COMPONENTS calls"
Passes through a raw query string without modification.
Examples
iex> Dllb.Query.raw("INFO FOR DB")
"INFO FOR DB"
Builds a RELATE statement to create a graph edge between two records.
Examples
iex> Dllb.Query.relate("user:a", "follows", "user:b", %{since: "2024"})
"RELATE user:a->follows->user:b SET since = '2024'"
Builds a REMOVE INDEX statement that drops a secondary index and all of
its catalog entries. Subsequent queries fall back to full scans.
Examples
iex> Dllb.Query.remove_index("user", "by_age")
"REMOVE INDEX by_age ON TABLE user"
Builds a SEARCH statement: a BM25 full-text query against a field that
has a full-text index. Results come back as rows ranked best-first, each
carrying an extra score field.
Options
:limit- maximum number of hits to return
Examples
iex> Dllb.Query.search("article", "body", "graph database")
"SEARCH article body 'graph database'"
iex> Dllb.Query.search("article", "body", "graph database", limit: 5)
"SEARCH article body 'graph database' LIMIT 5"
@spec select(String.t(), select_opts()) :: String.t()
Builds a SELECT statement with optional clauses.
Options
:fields- list of field names to select (default["*"]):where- WHERE clause string:order- ORDER BY clause string:limit- LIMIT value:fetch- graph traversal fetch clause (e.g."->calls->fn_node")
Examples
iex> Dllb.Query.select("user", where: "age > 25", limit: 10)
"SELECT * FROM user WHERE age > 25 LIMIT 10"
Builds an UPDATE statement for an existing record.
Examples
iex> Dllb.Query.update("user:u1", %{name: "Bob"})
"UPDATE user:u1 SET name = 'Bob'"
Builds an UPDATE <table> SET ... WHERE <clause> statement that updates
every row matching the (already-built) WHERE clause.
Only the listed fields are changed (partial-update semantics). An empty WHERE string updates all rows in the table.
Examples
iex> Dllb.Query.update_where("ast_node", %{arity: 1}, "kind = 'function_def'")
"UPDATE ast_node SET arity = 1 WHERE kind = 'function_def'"
Builds a CREATE ... ON CONFLICT UPDATE statement for idempotent upserts.
If the record already exists (by table + id), the conflict is resolved by updating it instead of failing:
- with no
update_fields(or an empty map), the engine merges the samefieldsfrom the CREATE into the existing record (ON CONFLICT UPDATE); - with a non-empty
update_fieldsmap, the engine applies those explicit fields to the existing record instead (ON CONFLICT UPDATE SET ...).
Examples
iex> Dllb.Query.upsert("user", "u1", %{name: "Alice", age: 30})
"CREATE user:u1 SET age = 30, name = 'Alice' ON CONFLICT UPDATE"
iex> Dllb.Query.upsert("user", "u1", %{name: "Alice", age: 30}, %{age: 31})
"CREATE user:u1 SET age = 30, name = 'Alice' ON CONFLICT UPDATE SET age = 31"
Builds a VECTOR SEARCH statement: an approximate nearest-neighbour query
against a field that has a vector index. vector is the query embedding
(a list of numbers). Results come back as rows ordered nearest-first, each
carrying an extra distance field.
Options
:k- number of nearest neighbours to return
Examples
iex> Dllb.Query.vector_search("doc", "embedding", [0.1, 0.2, 0.3])
"VECTOR SEARCH doc embedding [0.1, 0.2, 0.3]"
iex> Dllb.Query.vector_search("doc", "embedding", [0.1, 0.2, 0.3], k: 5)
"VECTOR SEARCH doc embedding [0.1, 0.2, 0.3] K 5"