Querying LoraDB with Cypher
LoraDB speaks a pragmatic subset of Cypher. Queries are strings that chain clauses — see the clause reference below, or jump into the Ten-Minute Tour for a guided run-through.
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
WHERE p.active = true
RETURN p.name, c.name
ORDER BY p.nameEach clause reads the rows emitted by the previous one and passes rows
forward. RETURN ends the pipeline.
Anatomy of a query
MATCH — find patterns (produces rows)
↓
WHERE — filter rows (drops rows)
↓
WITH — project + optionally group (reshapes rows)
↓
WHERE — filter rows post-aggregate (HAVING-style)
↓
RETURN — project + sort + paginate (final shape)
Not every query uses every stage. The important invariant: each clause sees the rows produced by the previous one.
Clause reference
| Clause | Purpose |
|---|---|
| MATCH | Find patterns of nodes and relationships |
| CREATE | Create nodes and relationships |
| WHERE | Filter rows |
| Indexes | Declare, inspect, query, and drop secondary indexes |
| Constraints | Add uniqueness, existence, key, and type checks |
| RETURN / WITH | Project, rename, order, and page results |
| ORDER BY / SKIP / LIMIT | Sort and paginate |
| SET / REMOVE / DELETE | Mutate existing entities |
| UNWIND / MERGE | Iterate over lists; create-or-match |
| Aggregation | count, collect, avg, and group-by |
| Paths | Variable-length traversals and shortest paths |
For copy-paste examples covering every clause, see Query Examples. For a single-page terse reference, see the Cheat sheet.
Where common tasks live
| Task | Page |
|---|---|
| Look up by label + property | MATCH |
| Write new nodes/edges | CREATE |
| Upsert | MERGE |
| Bulk import | UNWIND + CREATE |
| Patch a property map | SET += |
| Replace all properties | SET = |
| Remove a property | REMOVE / SET n.p = null |
| Delete with edges | DETACH DELETE |
| Top-N | ORDER BY + LIMIT |
| Stable pagination | Keyset pagination |
| Group and aggregate | Aggregation walkthrough |
| HAVING-style filter | WITH … WHERE |
| Anti-join | NOT EXISTS |
| Speed up common predicates | CREATE INDEX |
| Enforce uniqueness or property shape | CREATE CONSTRAINT |
| Shortest path | shortestPath |
| Inline related list | Pattern comprehension |
| Per-row conditional value | CASE expressions |
| Count rows matching a condition | count(CASE WHEN … THEN 1 END) |
Execution model
- Queries execute atomically per auto-commit call. Rust and in-process bindings also expose explicit transactions; HTTP does not.
- Auto-commit reads can overlap on Arc snapshots. Write commits and explicit read-write transactions serialize. See Limitations → Concurrency.
- Names (labels, relationship types, property keys) are validated
against the live graph for
MATCH; any name is accepted byCREATE,MERGE, andSET. - Unknown function names are rejected at analysis time — see Functions.
Parameters
Any value that isn't a constant should use a parameter. The short version follows; Parameters has the full reference.
MATCH (p:Person) WHERE p.name = $name RETURN pParameters are bound at call time from the host language:
- Rust —
BTreeMap<String, LoraValue> - Node.js — plain object
- Python —
dict - WASM — plain object
- HTTP server — not yet supported, see Limitations → Parameters
Missing parameters resolve to null, which can silently produce empty
results — set them or validate inputs before executing.
Parameters vs inline literals
// Safe (parameterised)
MATCH (u:User) WHERE u.id = $id RETURN u
;// Unsafe if $id came from untrusted input and was inlined
MATCH (u:User) WHERE u.id = 42 RETURN uParameters are the only supported way to mix untrusted input into a query. They also let the query planner cache plans across invocations.
Parameter types
| Host value | LoraDB type |
|---|---|
null / None / undefined | Null |
bool | Boolean |
int (Python) / number (JS, integer) / i64 (Rust) | Integer |
float (Python) / number (JS, non-integer) / f64 (Rust) | Float |
str / String | String |
list / array / Vec | List |
dict / object / BTreeMap | Map |
host helpers (date(), wgs84(), …) | Date, Point, etc. |
Host helpers are binding APIs. In query text, use cast syntax for
typed construction, for example '2026-05-01'::DATE or
{x: 1, y: 2}::POINT.
What's not supported
See Limitations for the full list. Short
version: no general-purpose CALL, no FOREACH, no LOAD CSV, and no
multi-database (USE). Index and constraint DDL are supported for scoped
catalog entries; see Indexes and Constraints.
See also
- Ten-Minute Tour — guided walkthrough.
- Cheat sheet — single-page quick reference.
- Parameters — typed parameter binding.
- Query Examples — copy-paste recipes by shape.
- Cookbook — scenario-driven recipes.
- Functions — every built-in.
- Data types — value shapes for parameters and properties.
- Graph model — the underlying data model.
- Result formats — how results come back over the wire.