GraphLite SDK

December 2, 2025 · View on GitHub

High-level, ergonomic Rust SDK for GraphLite - the fast, embedded graph database.

Overview

The GraphLite SDK provides a developer-friendly API for working with GraphLite databases in Rust applications. It follows patterns from popular embedded databases like SQLite (rusqlite) while providing graph-specific features.

Features

  • Simple API - Clean, intuitive interface following SQLite/rusqlite conventions
  • Session Management - User context and permissions support
  • Transactions - ACID guarantees with automatic rollback (RAII pattern)
  • Query Builder - Fluent API for constructing GQL queries
  • Typed Results - Deserialize query results into Rust structs
  • Zero External Dependencies - Fully embedded, no server required
  • Connection Pooling - Efficient concurrent access (future)
  • Async Support - Full tokio integration (future)

Quick Start

Add to your Cargo.toml:

[dependencies]
graphlite-sdk = "0.1"

Basic usage:

use graphlite_sdk::{GraphLite, Error};

fn main() -> Result<(), Error> {
    // Open database
    let db = GraphLite::open("./mydb")?;

    // Create session
    let session = db.session("admin")?;

    // Execute query
    let result = session.query("MATCH (p:Person) RETURN p.name")?;

    for row in result.rows {
        println!("{:?}", row);
    }

    Ok(())
}

Core Concepts

Opening a Database

GraphLite is an embedded database - no server required. Just open a directory:

let db = GraphLite::open("./mydb")?;

This creates or opens a database at the specified path.

Sessions

Unlike SQLite, GraphLite uses sessions for user context and permissions:

let session = db.session("username")?;

Sessions provide:

  • User authentication and authorization
  • Transaction isolation
  • Audit logging

Executing Queries

Simple query execution:

let result = session.query("MATCH (n:Person) RETURN n")?;

Or for statements that don't return results:

session.execute("INSERT (:Person {name: 'Alice'})")?;

Transactions

Transactions follow the rusqlite pattern with automatic rollback:

// Transaction with explicit commit
let mut tx = session.transaction()?;
tx.execute("INSERT (:Person {name: 'Alice'}), (:Person {name: 'Bob'})")?;
tx.commit()?;  // Persist changes

// Transaction with automatic rollback
{
    let mut tx = session.transaction()?;
    tx.execute("INSERT (:Person {name: 'Charlie'})")?;
    // tx is dropped here - changes are automatically rolled back
}

Query Builder

Build queries fluently:

let result = session.query_builder()
    .match_pattern("(p:Person)")
    .where_clause("p.age > 25")
    .return_clause("p.name, p.age")
    .order_by("p.age DESC")
    .limit(10)
    .execute()?;

Typed Results

Deserialize results into Rust structs:

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    age: u32,
}

let result = session.query("MATCH (p:Person) RETURN p.name as name, p.age as age")?;
let typed = TypedResult::from(result);
let people: Vec<Person> = typed.deserialize_rows()?;

Examples

Basic CRUD Operations

use graphlite_sdk::GraphLite;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = GraphLite::open("./mydb")?;
    let session = db.session("admin")?;

    // Create schema and graph
    session.execute("CREATE SCHEMA example")?;
    session.execute("USE SCHEMA example")?;
    session.execute("CREATE GRAPH social")?;
    session.execute("USE GRAPH social")?;

    // Create nodes (multiple in one INSERT statement)
    session.execute("INSERT (:Person {name: 'Alice', age: 30}), (:Person {name: 'Bob', age: 25})")?;

    // Create relationships
    session.execute(
        "MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
         CREATE (a)-[:KNOWS]->(b)"
    )?;

    // Query
    let result = session.query(
        "MATCH (p:Person)-[:KNOWS]->(f:Person)
         RETURN p.name as person, f.name as friend"
    )?;

    for row in result.rows {
        println!("{:?}", row);
    }

    Ok(())
}

Transaction Example

use graphlite_sdk::GraphLite;

fn transfer_relationship(db: &GraphLite) -> Result<(), Box<dyn std::error::Error>> {
    let session = db.session("admin")?;

    let mut tx = session.transaction()?;

    // Delete old relationship
    tx.execute("MATCH (a)-[r:FOLLOWS]->(b) WHERE a.name = 'Alice' DELETE r")?;

    // Create new relationship
    tx.execute(
        "MATCH (a {name: 'Alice'}), (c {name: 'Charlie'})
         CREATE (a)-[:FOLLOWS]->(c)"
    )?;

    tx.commit()?;
    Ok(())
}

Query Builder Example

use graphlite_sdk::GraphLite;

fn find_active_users(db: &GraphLite) -> Result<(), Box<dyn std::error::Error>> {
    let session = db.session("admin")?;

    let result = session.query_builder()
        .match_pattern("(u:User)")
        .where_clause("u.status = 'active'")
        .where_clause("u.lastLogin > date('2024-01-01')")
        .with_clause("u, count(u.posts) as post_count")
        .where_clause("post_count > 10")
        .return_clause("u.name, u.email, post_count")
        .order_by("post_count DESC")
        .limit(20)
        .execute()?;

    for row in result.rows {
        println!("{:?}", row);
    }

    Ok(())
}

Typed Deserialization Example

use graphlite_sdk::{GraphLite, TypedResult};
use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct User {
    name: String,
    email: String,
    age: u32,
}

fn get_users(db: &GraphLite) -> Result<Vec<User>, Box<dyn std::error::Error>> {
    let session = db.session("admin")?;

    let result = session.query(
        "MATCH (u:User) RETURN u.name as name, u.email as email, u.age as age"
    )?;

    let typed = TypedResult::from(result);
    let users = typed.deserialize_rows::<User>()?;

    Ok(users)
}

API Comparison with SQLite

GraphLite SDK follows similar patterns to rusqlite but adapted for graph databases:

Operationrusqlite (SQLite)graphlite-sdk (GraphLite)
Open DBConnection::open()GraphLite::open()
Executeconn.execute()session.execute()
Queryconn.query_row()session.query()
Transactionconn.transaction()?session.transaction()?
Committx.commit()?tx.commit()?
Rollbacktx.rollback()? or droptx.rollback()? or drop

Key Differences:

  • GraphLite uses sessions for user context (SQLite doesn't have sessions)
  • GraphLite uses GQL (Graph Query Language) instead of SQL
  • GraphLite is optimized for graph data (nodes, edges, paths)

Architecture

Your Application


┌─────────────────────────┐
│   GraphLite SDK         │
│   - GraphLite           │  ← You are here
│   - Session             │
│   - Transaction         │
│   - QueryBuilder        │
│   - TypedResult         │
└─────────────────────────┘


┌─────────────────────────┐
│   GraphLite Core        │
│   - QueryCoordinator    │
│   - Storage Engine      │
│   - Catalog Manager     │
└─────────────────────────┘

Language Bindings

The GraphLite SDK is specifically for Rust applications. For other languages:

  • Python - Use bindings/python/ (via FFI)
  • Java - Use bindings/java/ (via JNI)
  • JavaScript/Node.js - Use bindings/javascript/ (via FFI/WASM)
  • Kotlin - Use bindings/kotlin/ (via JNI)

See the main MULTI_LANGUAGE_BINDINGS_DESIGN.md for details.

Performance

GraphLite SDK provides zero-overhead abstractions:

  • Direct Rust function calls (no FFI overhead)
  • No serialization for query results (unlike language bindings)
  • Compile-time optimizations
  • Same performance as using the core library directly

Benchmark comparison:

  • Rust SDK: ~100% of native performance
  • Python bindings (via FFI): ~80-90% of native
  • JavaScript bindings (via WASM): ~70-80% of native

Documentation

Examples

Run the examples:

# Basic usage example
cargo run --example basic_usage

# More examples coming soon

Contributing

Contributions welcome! Areas where help is needed:

  • ORM Features - Derive macros for mapping structs to graph nodes
  • Query Macros - Compile-time query validation
  • Async Support - Full tokio integration
  • Connection Pooling - Multi-threaded access patterns
  • Graph Algorithms - Built-in graph algorithms (shortest path, centrality, etc.)

License

Apache-2.0 - See LICENSE for details.