CREATE SCHEMA

Defines a new node type (schema) with named, typed fields.

Syntax DDL
CREATE SCHEMA SchemaName (
    field1: TYPE,
    field2: TYPE,
    ...
);
Example
CREATE SCHEMA User (
    name: STRING,
    age:  INT64
);

CREATE SCHEMA Company (
    name: STRING,
    revenue: FLOAT64
);

CREATE EDGE SCHEMA WORKS_AT (
    since: INT64,
    role: STRING
);

CREATE NODE

Creates a new node of a given schema. Optionally returns the auto-assigned ID.

Syntax DML
CREATE NODE SchemaName ( field = value, ... ) [RETURN id];
Example
CREATE NODE User (name = "Alice", age = 30) RETURN id;
CREATE NODE User (name = "Bob",   age = 25);
CREATE NODE Company (name = "Google", revenue = 300.5);
Note: Every node receives a per-schema id automatically (each schema has its own counter starting from 0). Use RETURN id to see the assigned ID.

CREATE EDGE

Creates a directed edge between two nodes. Nodes are referenced by Schema(id) or property lookup.

Syntax DML
CREATE [UNIQUE] EDGE edge_type
    FROM Schema(id)
    TO   Schema(id);
Examples
// By ID
CREATE EDGE friend FROM User(0) TO User(1);

// By property lookup
CREATE EDGE works_at
    FROM (User{name = "Alice"})
    TO   (Company{name = "Google"});

// Unique edge (prevents duplicates)
CREATE UNIQUE EDGE manages
    FROM User(0) TO User(1);
Current limitation: CREATE EDGE ... WITH (...) property assignment is not yet wired in the shell. Create the edge first, then set properties with UPDATE MATCH ... SET e.field = ....

MATCH

The primary query statement. Uses Cypher-inspired pattern syntax to traverse the graph.

Syntax QUERY
MATCH <pattern> [, <pattern> ...]
    [WHERE <condition>]
    [SELECT <fields>];

Node Patterns

Syntax
(alias:SchemaName)      // bind alias to schema
(alias)                   // alias only (schema inferred)

Edge Patterns

Syntax
// Outgoing edge
-[:EDGE_TYPE JOIN]->
-[e:EDGE_TYPE JOIN]->   // bind edge alias

// Incoming edge
<-[:EDGE_TYPE JOIN]-

Full Examples

Example — Simple traversal
MATCH (u:User)-[:friend INNER]->(f:User)
    WHERE u.age > 25
    SELECT u.name, f.name;
Example — Multi-hop traversal
MATCH (u:User)-[:friend INNER]->(f:User)
              -[:works_at INNER]->(c:Company)
    WHERE c.name = "Google"
    SELECT u.name, f.name, c.name;
Example — LEFT JOIN (keep unmatched sources)
MATCH (u:User)-[:friend LEFT]->(f:User)
    SELECT u.name, f.name;

// Result: all users, f.name = NULL if no friends
Example — Multiple patterns (comma-separated)
MATCH (u:User)-[:friend INNER]->(f:User),
      (f)-[:works_at INNER]->(c:Company)
    SELECT u.name, c.name;

DELETE

Removes nodes or edges from the graph.

Syntax
// Delete a specific node by ID
DELETE User(123);

// Delete nodes matching a pattern
DELETE (u:User) WHERE u.age < 18;

// Delete edges by type + direction
DELETE EDGE friend FROM User(0) TO User(1);

// Delete all outgoing edges of a type from a node
DELETE EDGE friend FROM User(0);

// Delete all incoming edges of a type to a node
DELETE EDGE works_at TO Company(0);

UPDATE

Modifies field values on existing nodes. Supports three forms: by ID (direct), by pattern (single schema + optional WHERE), and by MATCH (traversals / joins + optional WHERE).

Form 1 — Update by ID

Targets a single node using Schema(id). Field names are bare (no alias prefix).

Syntax DML
UPDATE Schema(id) SET field = value [, field = value ...] ;
Examples
// Update a single field
UPDATE User(0) SET age = 31;

// Update multiple fields at once (creates one version)
UPDATE User(0) SET name = "Alice B.", age = 31;

Form 2 — Update by Pattern

Uses a node pattern (alias:Schema) with an optional WHERE clause to match nodes. Field names must be alias-qualified (alias.field).

Syntax DML
UPDATE (alias:Schema) SET alias.field = value [, ...]
    [WHERE alias.field op value] ;
Examples
// Update all users named Alice
UPDATE (u:User) SET u.age = 31
    WHERE u.name = "Alice";

// Update with compound condition
UPDATE (u:User) SET u.name = "Senior"
    WHERE u.age > 30 AND u.age < 50;

// Update all nodes of a schema (no WHERE)
UPDATE (u:User) SET u.age = 0;

Form 3 — Update by MATCH (traversals / joins)

Uses a full MATCH pattern with traversals to find nodes across multiple schemas, then applies SET assignments. Field names must be alias-qualified. Multiple schemas can be updated in a single statement, including edge aliases.

Syntax DML
UPDATE MATCH (a:Schema1)-[e:EDGE_TYPE]->(b:Schema2)
    SET a.field = value [, b.field = value ...] [, e.field = value ...]
    [WHERE alias.field op value] ;
Examples
// Update both user and company for a traversal
UPDATE MATCH (u:User)-[:WORKS_AT]->(c:Company)
    SET u.employed = true, c.size = 1
    WHERE c.name = "Acme Corp";

// Update only one side of the relationship
UPDATE MATCH (u:User)-[:WORKS_AT]->(c:Company)
    SET u.status = "employed"
    WHERE c.name = "Google";

// Same-schema traversal (e.g. friends)
UPDATE MATCH (a:User)-[:FRIEND]->(b:User)
    SET a.has_friend = true, b.has_friend = true;

// Update edge properties by alias
UPDATE MATCH (u:User)-[e:WORKS_AT]->(c:Company)
    SET e.since = 2025, e.role = "engineer"
    WHERE u.name = "Alice";
Versioning: When multiple fields are updated in a single SET clause, TundraDB creates one version for the entire batch — not one per field.
Pattern/MATCH forms require alias prefix: SET age = 31 is only valid in the by-ID form. In pattern and MATCH forms you must write SET u.age = 31.

COMMIT

Persists the current database state to disk (Parquet files + JSON metadata).

Syntax
COMMIT;
Note: Without COMMIT, data lives in-memory only. Call COMMIT before shutting down to persist.

SHOW

Inspect edge data and available edge types.

Syntax
// List all edge types
SHOW EDGE TYPES;

// Show edges of a specific type
SHOW EDGES friend;

WHERE Clause

Filters results using boolean expressions. Supports AND, OR, and parenthesized grouping. Works for node aliases and edge aliases (for example, e.since).

Syntax
WHERE alias.field operator value
      [AND|OR alias.field operator value]
Examples
WHERE u.age >= 25 AND u.age < 40

WHERE c.name = "Google" OR c.name = "Apple"

WHERE e.since >= 2025

WHERE (u.age > 30 AND u.name = "Alice") OR u.age < 20

SELECT Clause

Choose which fields to include in the result table. Supports aliasing with AS, edge field selection, and selecting a full edge alias.

Syntax
SELECT alias.field [AS alias_name], ...
SELECT e;  // full edge alias expansion
Example
MATCH (u:User)-[:works_at INNER]->(c:Company)
    SELECT u.name AS employee, c.name AS company, u.age;

MATCH (u:User)-[e:WORKS_AT]->(c:Company)
    SELECT u.name, e.since, e;

SET Clause

Specifies field assignments in an UPDATE statement. Comma-separated list of field = value pairs.

Syntax
SET field = value [, field = value ...]
Update Form Field Name Format Example
By ID Bare name SET name = "Alice", age = 31
By Pattern Alias-qualified SET u.name = "Alice", u.age = 31
Batch semantics: All assignments in a single SET clause are applied atomically — one version is created per node, regardless of how many fields are changed.

JOIN Types

Specified inside the edge pattern -[:EDGE_TYPE JOIN]->. Controls how unmatched nodes are handled.

Join Sources Targets Description
INNER Only matched Only matched Default. Both sides must have a connection.
LEFT All kept Only matched Keep all source nodes; target = NULL if no edge.
RIGHT Only matched All kept Keep all target nodes; source = NULL if no edge.
FULL All kept All kept Keep both sides. NULLs for unmatched on either side.
Side-by-side comparison
// INNER: only Alice (has a friend)
MATCH (u:User)-[:friend INNER]->(f:User);

// LEFT: all users, f=NULL for users without friends
MATCH (u:User)-[:friend LEFT]->(f:User);

// FULL: all users on both sides, NULLs where no match
MATCH (u:User)-[:friend FULL]->(f:User);
Self-join caveat: When source and target are the same schema (e.g., User → User), FULL/RIGHT joins use unmatched = all_target_ids - matched_source_ids to avoid duplicates. For cross-schema joins, it uses all_target_ids - matched_target_ids.

Data Types

TundraQLInternalArrowDescription
STRINGValueType::STRINGutf8Variable-length UTF-8 string
INT64ValueType::INT64int6464-bit signed integer
FLOAT64ValueType::DOUBLEfloat6464-bit floating point
ValueType::INT32int3232-bit signed integer (C++ API only)
ValueType::FLOATfloat3232-bit floating point (C++ API only)
ValueType::BOOLbooleanBoolean (C++ API only)
FIXED_STRING16/32/64utf8Fixed-size strings for memory optimization
Storage note: Strings use a tiered StringArena — short strings (≤16/32/64 bytes) are stored in fixed-size pools for cache efficiency. Longer strings go into a variable-length pool.

Operators

OperatorMeaningExample
=Equalu.name = "Alice"
!=Not equalu.age != 30
>Greater thanu.age > 25
>=Greater or equalu.age >= 25
<Less thanu.age < 40
<=Less or equalu.age <= 40
ANDLogical andu.age > 20 AND u.age < 40
ORLogical oru.name = "Alice" OR u.name = "Bob"

Pattern Syntax Reference

Complete pattern grammar used in MATCH and DELETE statements.

Grammar (EBNF-style)
pattern      :=  nodePattern ( edgePattern nodePattern )*
nodePattern  :=  '(' alias [ ':' Schema ] ')'
edgePattern  :=  '-[' [ ':' type ] [ join ] ']->'      // outgoing
              |  '<-[' [ ':' type ] [ join ] ']-'      // incoming
join         :=  INNER | LEFT | RIGHT | FULL
value        :=  STRING_LITERAL | INTEGER | FLOAT
Complete session example
// 1. Define schemas
CREATE SCHEMA User (name: STRING, age: INT64);
CREATE SCHEMA Company (name: STRING, size: INT64);

// 2. Create nodes
CREATE NODE User (name = "Alice", age = 30) RETURN id;
CREATE NODE User (name = "Bob",   age = 25) RETURN id;
CREATE NODE Company (name = "Google", size = 3000); // → Company id: 0

// 3. Create edges (IDs are per-schema: User has 0,1 — Company has 0)
CREATE EDGE friend   FROM User(0) TO User(1);
CREATE EDGE works_at FROM User(1) TO Company(0);

// 4. Query: Alice's friends who work at Google
MATCH (u:User)-[:friend INNER]->(f:User)
              -[:works_at INNER]->(c:Company)
    WHERE u.name = "Alice" AND c.name = "Google"
    SELECT u.name AS user, f.name AS friend, c.name AS company;

// 5. Update: Alice turned 31
UPDATE User(0) SET age = 31;

// 6. Bulk update: set all users older than 30 to "Senior"
UPDATE (u:User) SET u.name = "Senior" WHERE u.age > 30;

// 7. Update with MATCH (traversal) — set employed flag for Google employees
UPDATE MATCH (u:User)-[:works_at]->(c:Company)
    SET u.name = "Employed"
    WHERE c.name = "Google";

// 8. Persist
COMMIT;