SQL Interface Reference

GraphQLite is a standard SQLite extension. Once loaded, it registers SQL scalar functions and creates the graph schema in the current database.


Loading the Extension

SQLite shell

.load ./libgraphqlite
SELECT graphqlite_test();

Python (manual)

import sqlite3
conn = sqlite3.connect(":memory:")
conn.enable_load_extension(True)
conn.load_extension("./libgraphqlite")

Python (via graphqlite)

import graphqlite
conn = graphqlite.connect(":memory:")

Rust

#![allow(unused)]
fn main() {
let conn = graphqlite::Connection::open_in_memory()?;
}

Entry point symbol: sqlite3_graphqlite_init

On initialization the extension:

  1. Creates all schema tables (if not already present).
  2. Creates all indexes.
  3. Registers the SQL functions listed below.

Registered SQL Functions

cypher(query [, params_json])

SELECT cypher('MATCH (n:Person) RETURN n.name, n.age');
SELECT cypher('MATCH (n:Person) WHERE n.age > $min RETURN n.name', '{"min": 25}');

Arguments

ArgumentTypeRequiredDescription
queryTEXTYesCypher query string
params_jsonTEXT (JSON)NoJSON object; keys map to $name placeholders

Returns: TEXT — a JSON array of objects. Each object represents one result row. Keys are the column names from the RETURN clause. A query with no results returns [].

Result format

[
  {"n.name": "Alice", "n.age": 30},
  {"n.name": "Bob",   "n.age": 25}
]

For a single-column result the key is the expression text or alias from RETURN. For write queries with no RETURN clause, the result is a plain text status string such as "Query executed successfully - nodes created: N, relationships created: M". The empty array [] is only returned when a RETURN clause produced zero matching rows.

Error handling: Sets SQLite error text and returns an error result on parse failure or execution failure.


cypher_validate(query)

SELECT cypher_validate('MATCH (n:Person) RETURN n.name');

Validates a Cypher query without executing it.

Returns: TEXT — a JSON object:

{"valid": true}

or

{"valid": false, "error": "...", "line": 1, "column": 15}

regexp(pattern, string)

SELECT regexp('^Al.*', 'Alice');   -- 1
SELECT regexp('^Al.*', 'Bob');     -- 0

POSIX extended regular expression (ERE) match. Used internally to implement the =~ operator. Returns 1 if string matches pattern, 0 otherwise. The (?i) prefix enables case-insensitive matching.

Arguments

ArgumentTypeDescription
patternTEXTPOSIX extended regular expression (ERE)
stringTEXTString to test

Returns: INTEGER (1 or 0)


gql_load_graph()

SELECT gql_load_graph();

Load the graph adjacency structure into an in-memory cache for algorithm execution. Must be called before running graph algorithm functions.

Returns: TEXT — JSON status object: {"status": "loaded", "nodes": N, "edges": M}. If the graph is already loaded, returns {"status": "already_loaded", "nodes": N, "edges": M} instead.


gql_unload_graph()

SELECT gql_unload_graph();

Release the in-memory adjacency cache.

Returns: TEXT — JSON status object: {"status": "unloaded"}


gql_reload_graph()

SELECT gql_reload_graph();

Unload and reload the cache. Use after bulk data changes to refresh the algorithm cache.

Returns: TEXT — JSON status object: {"status": "reloaded", "nodes": N, "edges": M}


gql_graph_loaded()

SELECT gql_graph_loaded();

Check whether the adjacency cache is currently loaded.

Returns: TEXT — JSON object: {"loaded": true, "nodes": N, "edges": M} if loaded, {"loaded": false, "nodes": 0, "edges": 0} if not.


graphqlite_test()

SELECT graphqlite_test();

Smoke-test function. Returns a success string if the extension is loaded and functioning.

Returns: TEXT — "GraphQLite extension loaded successfully!"


Query Patterns

Read and iterate rows in Python

import json, sqlite3, graphqlite

conn = graphqlite.connect("graph.db")
raw = conn.execute("SELECT cypher('MATCH (n:Person) RETURN n.name, n.age')").fetchone()[0]
rows = json.loads(raw)
for row in rows:
    print(row["n.name"], row["n.age"])

Parameterized query via SQL

SELECT cypher(
  'MATCH (n:Person) WHERE n.age > $min RETURN n.name',
  json_object('min', 25)
);

Write query

SELECT cypher('CREATE (:Person {name: ''Alice'', age: 30})');

String literals inside Cypher must use single quotes. To embed a literal single quote in a SQL string, double it: ''.


Transaction Behavior

  • The cypher() function participates in the current SQLite transaction.
  • Write operations (CREATE, MERGE, SET, DELETE, etc.) are not auto-committed; wrap in BEGIN/COMMIT for explicit control.
  • gql_load_graph() reads a snapshot at call time; subsequent writes are not reflected until gql_reload_graph() is called.

Example

BEGIN;
SELECT cypher('CREATE (:Person {name: ''Alice''})');
SELECT cypher('CREATE (:Person {name: ''Bob''})');
COMMIT;

Direct Schema Access

The graph schema tables are ordinary SQLite tables. You can query them directly for inspection or integration.

-- Count nodes by label
SELECT label, count(*) FROM node_labels GROUP BY label;

-- List all property keys
SELECT key FROM property_keys ORDER BY key;

-- Find all text properties for node 1
SELECT pk.key, np.value
FROM node_props_text np
JOIN property_keys pk ON pk.id = np.key_id
WHERE np.node_id = 1;

Direct writes to schema tables bypass Cypher validation and the property key cache. Prefer cypher() for mutations.