Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cypher Query Language

LatticeDB implements a subset of the openCypher query language for graph operations. This chapter covers the supported syntax and patterns.

Query Structure

A typical Cypher query follows this structure:

MATCH <pattern>
WHERE <predicate>
RETURN <expression>
ORDER BY <expression>
SKIP <number>
LIMIT <number>

MATCH Clause

Node Patterns

Match all nodes:

MATCH (n) RETURN n

Match nodes with a label:

MATCH (n:Person) RETURN n

Match nodes with multiple labels:

MATCH (n:Person:Employee) RETURN n

Match nodes with properties:

MATCH (n:Person {name: "Alice"}) RETURN n

Relationship Patterns

Match outgoing relationships:

MATCH (a)-[r]->(b) RETURN a, r, b

Match with relationship type:

MATCH (a)-[r:KNOWS]->(b) RETURN a, b

Match with multiple relationship types:

MATCH (a)-[r:KNOWS|WORKS_WITH]->(b) RETURN a, b

Match in either direction:

MATCH (a)-[r:KNOWS]-(b) RETURN a, b

Variable-Length Paths

Match paths of specific length:

MATCH (a)-[*2]->(b) RETURN a, b  -- Exactly 2 hops

Match paths within a range:

MATCH (a)-[*1..3]->(b) RETURN a, b  -- 1 to 3 hops

Match paths up to a limit:

MATCH (a)-[*..5]->(b) RETURN a, b  -- Up to 5 hops

WHERE Clause

Comparison Operators

WHERE n.age > 25
WHERE n.age >= 25
WHERE n.age < 30
WHERE n.age <= 30
WHERE n.name = "Alice"
WHERE n.name <> "Bob"

Logical Operators

WHERE n.age > 25 AND n.active = true
WHERE n.role = "admin" OR n.role = "superuser"
WHERE NOT n.deleted

String Matching

WHERE n.name STARTS WITH "Al"
WHERE n.email ENDS WITH "@example.com"
WHERE n.description CONTAINS "important"

List Membership

WHERE n.status IN ["active", "pending"]
WHERE n.category IN $allowed_categories

NULL Checks

WHERE n.email IS NOT NULL
WHERE n.deleted IS NULL

Property Existence

WHERE exists(n.email)
WHERE NOT exists(n.deleted_at)

RETURN Clause

Return Nodes and Properties

RETURN n                    -- Return entire node
RETURN n.name              -- Return single property
RETURN n.name, n.age       -- Return multiple properties
RETURN n.name AS fullName  -- Alias

Aggregations

RETURN count(n)                    -- Count
RETURN count(DISTINCT n.category)  -- Distinct count
RETURN sum(n.amount)               -- Sum
RETURN avg(n.score)                -- Average
RETURN min(n.created_at)           -- Minimum
RETURN max(n.updated_at)           -- Maximum
RETURN collect(n.name)             -- Collect into list

Grouping

MATCH (n:Person)
RETURN n.department, count(n) AS count

ORDER BY, SKIP, LIMIT

Sorting

ORDER BY n.name              -- Ascending (default)
ORDER BY n.name ASC          -- Explicit ascending
ORDER BY n.name DESC         -- Descending
ORDER BY n.last_name, n.first_name  -- Multiple columns

Pagination

SKIP 10 LIMIT 20            -- Skip first 10, return next 20
LIMIT 100                   -- Return first 100

CREATE Clause

Create Nodes

CREATE (n:Person {name: "Alice", age: 30})

Create Relationships

MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"})
CREATE (a)-[:KNOWS {since: 2020}]->(b)

Create with RETURN

CREATE (n:Person {name: "Charlie"})
RETURN n

DELETE Clause

Delete Nodes

MATCH (n:Person {name: "DeleteMe"})
DELETE n

Delete Relationships

MATCH (a)-[r:KNOWS]->(b)
WHERE a.name = "Alice" AND b.name = "Bob"
DELETE r

DETACH DELETE (Nodes + Edges)

MATCH (n:Person {name: "DeleteMe"})
DETACH DELETE n  -- Deletes node and all its relationships

SET Clause

Update Properties

MATCH (n:Person {name: "Alice"})
SET n.age = 31

Set Multiple Properties

MATCH (n:Person {name: "Alice"})
SET n.age = 31, n.updated = true

Remove Property

MATCH (n:Person {name: "Alice"})
SET n.temp = NULL  -- Removes the property

Parameters

Use $ prefix for query parameters:

MATCH (n:Person {name: $name})
WHERE n.age > $min_age
RETURN n
LIMIT $limit

Rust Usage

#![allow(unused)]
fn main() {
use std::collections::HashMap;
use lattice_core::CypherValue;

let mut params = HashMap::new();
params.insert("name".to_string(), CypherValue::String("Alice".into()));
params.insert("min_age".to_string(), CypherValue::Int(25));
params.insert("limit".to_string(), CypherValue::Int(10));

let result = handler.query(
    "MATCH (n:Person {name: $name}) WHERE n.age > $min_age RETURN n LIMIT $limit",
    &mut engine,
    params,
)?;
}

REST API

curl -X POST http://localhost:6333/collections/my_collection/graph/query \
  -H "Content-Type: application/json" \
  -d '{
    "query": "MATCH (n:Person {name: $name}) RETURN n",
    "params": {
      "name": "Alice"
    }
  }'

Query Examples

Find Connected Nodes

-- Find all people Alice knows
MATCH (alice:Person {name: "Alice"})-[:KNOWS]->(friend)
RETURN friend.name

Find Paths

-- Find path from Alice to Bob (up to 4 hops)
MATCH path = (alice:Person {name: "Alice"})-[*1..4]->(bob:Person {name: "Bob"})
RETURN path

Aggregation Query

-- Count employees by department
MATCH (e:Employee)-[:WORKS_IN]->(d:Department)
RETURN d.name AS department, count(e) AS employee_count
ORDER BY employee_count DESC

Subgraph Extraction

-- Get a subgraph around a node
MATCH (center:Person {name: "Alice"})-[r*1..2]-(connected)
RETURN center, r, connected

Hybrid Vector + Graph

-- Find similar documents and their authors
MATCH (doc:Document)-[:AUTHORED_BY]->(author:Person)
WHERE doc.embedding <-> $query_embedding < 0.5
RETURN doc.title, author.name
ORDER BY doc.embedding <-> $query_embedding
LIMIT 10

Query Execution

Architecture

Query String
    │
    ▼
┌─────────────┐
│   Parser    │  Pest grammar → AST
└─────────────┘
    │
    ▼
┌─────────────┐
│  Planner    │  AST → Logical Plan
└─────────────┘
    │
    ▼
┌─────────────┐
│  Executor   │  Execute against storage
└─────────────┘
    │
    ▼
  Results

Handler API

#![allow(unused)]
fn main() {
use lattice_core::cypher::{CypherHandler, DefaultCypherHandler};

let handler = DefaultCypherHandler::new();

// Execute a query
let result = handler.query(
    "MATCH (n:Person) RETURN n.name",
    &mut engine,
    HashMap::new(),
)?;

// Process results
for row in result.rows {
    if let Some(name) = row.get("name") {
        println!("Name: {:?}", name);
    }
}

// Check execution stats
println!("Rows returned: {}", result.stats.rows_returned);
println!("Execution time: {:?}", result.stats.execution_time);
}

Limitations

Current implementation supports a subset of openCypher:

FeatureStatusNotes
MATCHSingle and multi-pattern
WHEREBasic predicates
RETURNProperties, aliases, aggregates
CREATENodes and relationships
DELETEWith DETACH
SETProperty updates
LIMIT/SKIPPagination
ORDER BYSingle/multi column
WITH⚠️Basic support
UNWIND⚠️Limited
MERGENot yet implemented
FOREACHNot yet implemented
CALLProcedures not supported

Next Steps