simple-triplestore

Crates.iosimple-triplestore
lib.rssimple-triplestore
version0.2.0-alpha.1
sourcesrc
created_at2024-07-26 16:34:11.985157
updated_at2024-08-01 17:59:04.135618
descriptionA simple graph database for storing triples with support for custom node and edge properties.
homepage
repositoryhttps://github.com/rcythr/simple-triplestore
max_upload_size
id1316407
size272,836
Richard Laughlin (rcythr)

documentation

README

simple-triplestore   Latest Docs Latest Crate

A triplestore implementation which can be used as a flexible graph database with support for custom node and edge properties.

Data Model

Each vertex and edge (collectively called nodes) are associated with an id (i.e. u64 or Ulid).

Property data is stored as

  • Id -> NodeProps
  • Id -> EdgeProps.

Graph relationships are stored three times as (Id, Id, Id) -> Id with the following sort orders:

  • Subject, Predicate, Object
  • Predicate, Object, Subject
  • Object, Subject, Predicate

This allows for any graph query to be decomposed into a range query on the lookup with the ideal ordering. For example,

  • query!{ a -b-> ? } becomes a query on the subject-predicate-object table.
  • query!{ ? -a-> b } becomes a query on the position-object-subject table.
  • query!{ a -?-> b } becomes a query on the object-subject-position table.

Supported Key-Value Backends

Example

Pull in various includes we need:

use ulid::Ulid;
use simple_triplestore::prelude::*;
let mut db = MemTripleStore::new(UlidIdGenerator::new());

Get some identifiers. In real applications these will come from an index or another lookup table.

let node_1 = Ulid(123);
let node_2 = Ulid(456);
let node_3 = Ulid(789);
let edge = Ulid(999);

Insert nodes and edges with user-defined property types. For a given TripleStore we can have one type for Nodes and one for Edges.

db.insert_node(node_1, "foo".to_string())?;
db.insert_node(node_2, "bar".to_string())?;
db.insert_node(node_3, "baz".to_string())?;
db.insert_edge(Triple{sub: node_1, pred: edge, obj: node_2}, Vec::from([1,2,3]))?;
db.insert_edge(Triple{sub: node_1, pred: edge, obj: node_3}, Vec::from([4,5,6]))?;

We can now query for edges which end at node_3, and find that there is only one.

assert_eq!(
  db.run(query!{ ? -?-> [node_3] })?
    .iter_edges(EdgeOrder::default())
    .map(|r| r.expect("ok"))
    .collect::<Vec<_>>(),
  [
    (Triple{sub: node_1, pred: edge, obj: node_3}, Vec::from([4,5,6])),
  ]
);

We can also query for all edges which have the predicate edge, and find both of the edges we added:

assert_eq!(
  db.run(query!{ ? -[edge]-> ? })?
    .iter_edges(EdgeOrder::default())
    .map(|r| r.expect("ok"))
    .collect::<Vec<_>>(),
  [
    (Triple{sub: node_1, pred: edge, obj: node_2}, Vec::from([1,2,3])),
    (Triple{sub: node_1, pred: edge, obj: node_3}, Vec::from([4,5,6])),
  ]
);
Commit count: 0

cargo fmt