Skip to content

Supported subset

NamiDB’s query layer implements a strict subset of Cypher 25 / openCypher 9 / GQL ISO/IEC 39075:2024, scoped to make LDBC SNB Interactive Complex Read IC01–IC14 parse, plan and run end to end. The subset is deliberately smaller than Neo4j Community 5.x or Kùzu; the trade is “what the parser accepts runs or returns a typed error — never a silent warning that changes semantics.”

When in doubt, an unsupported feature produces an explicit UnsupportedFeature error pointing at the RFC where it will land.

Standard reference

  • Base standard: GQL ISO/IEC 39075:2024 plus openCypher 9.
  • Cypher 25 (Neo4j) is used as a naming reference but no Neo4j-exclusive features are implemented (no db.* functions, no APOC).
  • When GQL and openCypher disagree, GQL wins.

See RFC-004 for the full scoping document.

Clauses

ClauseSupportedNotes
MATCHyesFixed and variable-length patterns.
OPTIONAL MATCHyesLeft-outer-join semantics.
WHEREyesArbitrary predicates over the visible scope.
RETURNyesProjection list with AS aliases. DISTINCT supported.
RETURN *yesAll bound aliases.
WITHyesPipe that re-opens scope. Supports inline WHERE and AS.
WITH *yesAll bound aliases (pipeline pass-through).
ORDER BYyesMulti-key ASC / DESC.
SKIP / LIMITyesLiterals or $param; no expressions.
UNWINDyesList → rows.
CREATEyesNodes and edges with literal or $param properties.
MERGEyesWith ON CREATE SET / ON MATCH SET. Single pattern part per MERGE (no multi-label).
SETyesProperty assign, property replace (=), property merge (+=), label add.
DELETE / DETACH DELETEyesSingle binding per delete. DELETE without DETACH fails if the node has edges.
REMOVEyesProperty remove, label remove.
UNION / UNION ALLyesSame arity and same aliases on each side.
shortestPath(...)yesWrapped form MATCH p = shortestPath((a)-[*..N]-(b)). Path binding required, single hop, finite upper bound.
allShortestPaths(...)yesSame shape as shortestPath; emits every distinct path of the minimum length.

Patterns

ElementSupportedNotes
(a:Label {prop: val})yesMulti-label (a:A:B). Inline map property filter.
-[r:TYPE]->yesDirections -->, <--, --.
Relationship type alternation -[r:A|B|C]->yesUnion over the listed types (RFC-024).
Variable-length -[r:KNOWS*1..3]->yesFinite bounds required. *..M is shorthand for *1..M.
Pattern chain (a)-[]-(b)-[]-(c)yes
Multi-part pattern MATCH (a), (b)yes
Anonymous variable (), []yes

Expressions

CategorySupported
Literals: int, float, string, bool, null, list [1,2,3], map {k: v}yes
Parameters $nameyes
Variable reference a, property access a.propyes
Arithmetic + - * / % ^yes
String + (concat), =~ (regex)yes
Boolean AND OR NOT XORyes
Comparison = <> < > <= >=yes
IS NULL / IS NOT NULLyes
IN (list membership)yes
STARTS WITH, ENDS WITH, CONTAINSyes
CASE WHEN … THEN … ELSE END (simple and multi-branch)yes
List comprehension [x IN list WHERE pred | expr]yes
Pattern comprehension [(a)-[]->(b) | b.name]yes
Pattern predicate WHERE (a)-[]->(b) / EXISTS { ... }yes

Types

INTEGER (64-bit signed), FLOAT (64-bit), STRING, BOOLEAN, NULL, LIST<T> (heterogeneous allowed, typecheck at runtime), MAP<STRING, T>, NODE, RELATIONSHIP, PATH, DATE, DATETIME (UTC, microseconds), DURATION, VECTOR(Vec<f32>).

Out of scope in v0: BYTES, POINT, LOCALDATETIME, ZONEDDATETIME, LOCALTIME, TIME.

NULL semantics

Three-valued logic:

  • NULL = NULLNULL (not true).
  • NULL AND falsefalse; NULL AND trueNULL.
  • WHERE rejects rows whose predicate evaluates to NULL (treated as false).
  • IS NULL / IS NOT NULL are the only forms that test for NULL.

LDBC SNB Interactive Complex coverage

Queryv0
IC1 — Friends by name (transitive)yes
IC2 — Recent messages by friendsyes
IC3 — Friends in two countriesyes
IC4 — New topics on friend postsyes
IC5 — New groups (membership count)yes
IC6 — Tag co-occurrenceyes
IC7 — Recent likersyes
IC8 — Recent repliesyes
IC9 — Recent messages by friends-of-friendsyes
IC10 — Friend recommendationyes
IC11 — Job referralyes
IC12 — Expert search by tag classyes
IC13 — Single shortest pathyes (RFC-023)
IC14 — All shortest paths weightedyes (RFC-023)

All 14 IC queries parse, lower and run end to end on the current main branch.

Out of scope (v0)

Anything not listed above is explicitly out of scope and produces a typed parse / lower error. Notable exclusions:

FeatureWhy it’s outWhere it lands
CALL { ... } (subqueries)Subquery scoping is subtle; not needed for LDBC IC.Future RFC
CALL procedure.name(...)No procedure registry. APOC explicitly excluded.Future RFC
FOREACHImperative; rarely useful in practice.Future RFC
USE databaseCross-database queries; single namespace per session.RFC for Cloud
LOAD CSVBulk-load happens through WriterSession / merge_nodes.Never via Cypher in v0.
CREATE INDEX / CREATE CONSTRAINTDDL handled by the schema API, not Cypher.Future RFC
EXPLAIN / PROFILE (as Cypher prefix)Available via the CLI namidb explain.Future RFC
Explicit transactions (BEGIN/COMMIT/ROLLBACK in Cypher)Auto-commit per query in v0.Never via Cypher in v0.
Variable-length without an upper bound (*1..)Blowup not bounded; rejected explicitly.Possible with WCOJ.
Zero-length patterns (*0..n)Semantics around auto-loops not finalised.Future RFC
MATCH p = (a)-[*]->(b) RETURN p (var-length path bindings)Path materialisation deferred.Future RFC
POINT, TIME, ZONEDDATETIME typesNot needed for LDBC SNB Interactive.Future RFC
db.* / apoc.* namespacesVendor-specific Neo4j; non-portable.Never

Read-your-own-writes

In v0, a single query that writes then reads does not see its own writes. Example:

CREATE (a:Person {name: 'Ada'})
MATCH (p:Person) RETURN p.name

The MATCH sees the snapshot pinned before the CREATE ran. The new Ada appears in the next query. Workaround: run writes and reads in two separate statements (or two separate Client.cypher calls — Cypher writes auto-commit at the end of each statement).

See RFC-009 for the rationale.

What’s next