Embedded database
oxgraph-db is a standalone, OxGraph-native database engine built directly on
the topology substrate. It owns durable database identity, cataloged physical
projections, typed properties and indexes, native OxQL execution, and embedded
transaction semantics — while the foundation crates stay storage- and
meaning-neutral.
It is the engine oxcode stores its code graph in.
Add it
cargo add oxgraph-dbThe same engine is reachable through the umbrella crate's db feature
(cargo add oxgraph --features db); depending on oxgraph-db directly is the
common path for database-only consumers.
A first database
A database is a directory. You create or open it, do all mutation inside a single-writer transaction that commits atomically, and read through a snapshot reader. Relations carry roles; a projection turns chosen relation types into a binary graph (or hypergraph) you can traverse, rank, and query.
use std::collections::BTreeSet;
use oxgraph_db::{
Db, GraphProjectionDefinition, Key, PageRankConfig, ProjectionDefinition, PropertyFamily,
PropertySubject, PropertyType, QueryValue, Text, Walk,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut db = Db::create("graph.oxgdb")?;
// One write transaction. It commits atomically when the closure returns Ok,
// and rolls back on Err.
let ((alice, calls), _outcome) = db.write(|w| {
let source = w.register_role("source")?;
let target = w.register_role("target")?;
let calls_type = w.register_relation_type("Calls")?;
let name = w.register_property_key("name", PropertyFamily::Element, PropertyType::Text)?;
let alice = w.create_element()?;
let bob = w.create_element()?;
w.set(PropertySubject::Element(alice), Key::<Text>::from_id(name), "alice".to_owned())?;
w.set(PropertySubject::Element(bob), Key::<Text>::from_id(name), "bob".to_owned())?;
// A directed relation alice -> bob, expressed as two role-typed incidences.
let edge = w.create_relation()?;
w.set_relation_type(edge, calls_type)?;
w.create_incidence(edge, alice, source)?;
w.create_incidence(edge, bob, target)?;
// A graph projection exposes the Calls relations as a binary graph.
let calls = w.define_projection(ProjectionDefinition::Graph(GraphProjectionDefinition {
name: "calls".to_owned(),
relation_types: BTreeSet::from([calls_type]),
source_role: source,
target_role: target,
}))?;
Ok((alice, calls))
})?;
let read = db.reader();
// OxQL: resolve elements by property.
let prepared = db.prepare("MATCH ELEMENTS WHERE name = 'alice'")?;
for row in read.run(&prepared)?.rows() {
if let [QueryValue::Element(id)] = row.values.as_slice() {
println!("matched element {}", id.get());
}
}
// Traverse the projection: alice -> bob.
let walk = read.walk(calls, &[alice], Walk::default())?;
println!("reached {} nodes from alice", walk.nodes().len());
// Personalized PageRank, seeded on alice, over the same projection.
let ranked = read.personalized_pagerank(calls, &[alice], PageRankConfig::new(0.85, 1e-6, 100))?;
println!("top element: {:?}", ranked.first().map(|(id, _)| id.get()));
Ok(())
}Transactions and isolation
- Single writer.
Db::writetakes the writer lock for the duration of the closure; a second concurrent write is rejected withWriterLockHeld. The closure returns a value and aCommitOutcome; returningErrrolls the transaction back. - Snapshot readers.
Db::readerpins a consistent snapshot. A reader keeps observing its pinned state across later commits (MVCC isolation); a fresh reader sees the new state.
Projections
A projection names a physical graph or hypergraph view over the catalog:
ProjectionDefinition::Graph— a binary graph over relation types with a source and target role. BFS, PageRank, longest-path, andWALK/NEIGHBORSrun over it.ProjectionDefinition::Hypergraph— a directed hypergraph over relation types with source and target role sets.
OxQL
Prepare a query, then run it against a reader. The engine accepts element and
relation matching, label and typed-property predicates (with AND/OR and
parentheses), and graph walks over a named projection.
CATALOG
MATCH ELEMENTS
MATCH ELEMENTS HAS LABEL <label>
MATCH ELEMENTS WHERE <property> = '<value>'
MATCH ELEMENTS WHERE <property> >= <number> AND ( <a> OR <b> )
MATCH RELATIONS TYPE <type>
GRAPH <projection> NEIGHBORS <element-id>
GRAPH <projection> WALK FROM <element-id> DEPTH <n> [DIRECTION outgoing|incoming|both] [LIMIT n]Predicates are schema-checked at prepare time: a type or property-family
mismatch (for example WHERE age = '42' on an integer key) is rejected before
execution, not silently coerced.
Durability and recovery
The engine is crash-safe by construction. Writes go to a CRC-checked log;
compact folds committed deltas into a base. On open, a torn final log frame is
truncated and the prior committed frame recovered, while corruption inside an
already-committed frame or the base fails loudly (LogCorrupt / InvalidStore)
rather than being skipped.
Reference
The full public surface — Db, Reader, Writer, the catalog and schema
types, traversal, and query results — is documented on
docs.rs/oxgraph-db.