4个版本

0.1.0-alpha.32019年12月8日
0.1.0-alpha.22019年11月28日
0.1.0-alpha.12019年11月27日

#51 in #atom

Apache-2.0/MIT

76KB
1.5K SLoC

g1

简单的图存储。

模型

原子:原子是图中的节点。每个原子都表示为一个UUID。

名称:名称唯一标识一个原子。它们有一个命名空间和一个标题,两者都是字符串。

:边是定向的,两端都有一个原子。边与一个字符串标签相关联。两个具有给定标签的原子之间最多只能存在一条边。

标签:标签附加到原子上。它们有一个键和一个值,两者都是字符串。

Blob:Blob附加到原子上。它们有一个类型,这是一个字符串;一个类型,这是一个MIME类型;以及内容,这是一个任意大小的二进制字符串。Blob通过SHA256散列来引用。

字符串是UTF-8字符串,长度不应超过256字节。

Rust API

目前,只实现了简单操作

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(())
}

依赖关系

~8–13MB
~212K SLoC