4 releases
0.1.0-alpha.3 | Dec 8, 2019 |
---|---|
0.1.0-alpha.2 | Nov 28, 2019 |
0.1.0-alpha.1 | Nov 27, 2019 |
#47 in #atom
80KB
1.5K
SLoC
g1
A simple graph store.
Model
Atom: Atoms are the nodes of the graph. Each is represented as a UUID.
Name: Names uniquely identify an atom. They have a namespace and a title, both of which are strings.
Edge: Edges are directed, with an atom at both endpoints. Edges have a string label associated with them. At most one edge between two atoms with a given label may exist.
Tag: Tags are attached to atoms. They have a key and a value, both of which are strings.
Blob: Blobs are attached to atoms. They have a kind, which is a string; a type, which is a MIME type; and contents, which are an arbitrarily large binary string. Blobs are referred to by a SHA256 hash.
Strings are UTF-8 strings, which should be no longer than 256 bytes.
Rust API
For now, only simple operations are implemented:
use anyhow::{anyhow, Result};
use defer::defer;
use futures::prelude::*;
use g1::{query, Atom, Connection, SqliteConnection};
#[tokio::main]
async fn main() -> Result<()> {
let mut db_dir = std::env::temp_dir();
db_dir.push("g1-readme-example");
std::fs::create_dir_all(&db_dir)?;
let _guard = defer(|| {
std::fs::remove_dir_all(&db_dir).unwrap();
});
let conn = SqliteConnection::open(db_dir.clone()).await?;
conn.create_name(conn.create_atom().await?, "example/readme", "foo", false)
.await?;
conn.create_name(conn.create_atom().await?, "example/readme", "bar", false)
.await?;
let foo = conn
.query_first(query! { ?- name(Atom, "example/readme", "foo"). })
.await?
.ok_or_else(|| anyhow!("couldn't find foo"))?[0]
.parse()?;
let bar = conn
.query_first(query! { ?- name(Atom, "example/readme", "bar"). })
.await?
.ok_or_else(|| anyhow!("couldn't find bar"))?[0]
.parse()?;
conn.create_name(bar, "other namespace", "bar", false)
.await?;
assert_eq!(
conn.query_first(query! { ?- name(Atom, "other namespace", "bar"). })
.await?
.ok_or_else(|| anyhow!("couldn't find bar"))?[0]
.parse::<Atom>()?,
bar
);
conn.create_edge(foo, bar, "next").await?;
conn.create_edge(bar, foo, "prev").await?;
let edges = conn.query_all(query! { ?- edge(From, To, Label). }).await?;
assert!(edges.contains(&vec![
foo.to_string().into(),
bar.to_string().into(),
"next".to_string().into()
]));
assert!(edges.contains(&vec![
bar.to_string().into(),
foo.to_string().into(),
"prev".to_string().into()
]));
conn.create_tag(foo, "letters", "3", false).await?;
let hash = conn
.store_blob(stream::once(future::ok((b"bar" as &[_]).into())).boxed())
.await?;
conn.create_blob(
bar,
"name again",
"text/plain".parse().unwrap(),
hash,
false,
)
.await?;
Ok(())
}
Dependencies
~7–13MB
~196K SLoC