Dllb

dllb

Elixir client for the dllb multi-model NoSQL database

Hex.pmHex Docs

Dllb provides a high-level Elixir API for communicating with the dllb database over TCP. It manages a NimblePool-based connection pool, speaks the dllb line-based wire protocol, and exposes a query builder plus result parsing so your application can focus on data rather than sockets.

Features

Installation

Add dllb to your list of dependencies in mix.exs:

def deps do
[
{:dllb, "~> 0.1.0"}
]
end

Configuration

# config/config.exs
config :dllb,
enabled: true,
host: "127.0.0.1",
port: 3009,
pool_size: 5,
outcome: :json,
timeout: 30_000

Setting enabled: false (the default) starts the application without the connection pool, which is useful for compile-time or test environments where no dllb server is available.

Options

Usage

Basic queries

{:ok, %Dllb.Result.Rows{count: 3, data: rows}} = Dllb.query("SELECT * FROM users")
result = Dllb.query!("SELECT * FROM users WHERE age > 25")

Query builder

Dllb.Query.create("user", %{name: "Alice", age: 30})
# => "CREATE user SET age = 30, name = 'Alice'"
Dllb.Query.select("user", where: "age > 25", limit: 10)
# => "SELECT * FROM user WHERE age > 25 LIMIT 10"
Dllb.Query.relate("user:a", "follows", "user:b", %{since: "2024"})
# => "RELATE user:a->follows->user:b SET since = '2024'"

Secondary indexes

# Single-field secondary index.
Dllb.Query.define_index("user", "by_age", ["age"])
# => "DEFINE INDEX by_age ON TABLE user FIELDS age"
# Composite index (leftmost-prefix planning: list the leading field first).
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"
# Unique constraint over the full indexed tuple.
Dllb.Query.define_index("user", "by_email", ["email"], unique: true)
# => "DEFINE INDEX by_email ON TABLE user FIELDS email UNIQUE"
# Drop an index (queries then fall back to full scans).
Dllb.Query.remove_index("user", "by_age")
# => "REMOVE INDEX by_age ON TABLE user"

Once an index exists, no query changes are required: SELECT, COUNT, and UPDATE statements whose WHERE clause has equality or range predicates on indexed fields are accelerated automatically.

Vector (HNSW) and full-text index creation are not part of the engine's query protocol, so they cannot be defined over the wire.

Upserts

# Insert, or merge the same fields on conflict.
Dllb.Query.upsert("user", "u1", %{name: "Alice", age: 30})
# => "CREATE user:u1 SET age = 30, name = 'Alice' ON CONFLICT UPDATE"
# Insert, or apply explicit fields on conflict.
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"

Schema bootstrap

{:ok, :bootstrapped} = Dllb.Schema.bootstrap(&Dllb.query/1)

MetaAST ingestion

context = %{language: :elixir, file_path: "/app/lib/parser.ex"}
{:ok, %{nodes: 42, edges: 17}} = Dllb.MetaAST.ingest_tree(ast, context, &Dllb.query/1)

Modules

Documentation

hexdocs.pm/dllb

Credits

Created as part of the Oeditus code quality tooling ecosystem.

License

MIT