1个不稳定版本

0.1.0 2020年11月1日

#274数据库实现

MIT 许可证

200KB
5K SLoC

codd

codd 是一个库,用于在内存中单调增长的CO/DD数据库中评估类型化的关系表达式。CO/DD主要开发用于支持基于关系代数的razor的实现,但其设计符合数据库理论的常见概念,也可以用作最小通用数据库。

CO/DD中的数据库实例实现借鉴自 datafrog

  • Instance<T> (Variable<T>datafrog 中) 包含类型为 T 的元组,
  • 通过维护三个集合 to_add(待插入的候选元组)、recent(最近添加的元组)和 stable(已反映在所有视图中的旧元组)来实现增量视图维护。

相比之下,CO/DD区分了关系实例和视图,并提供了一个特性 Expression<T> 和实现 Expression<T> 的类型来查询数据库。

《CODD》中的关系代数和数据库术语借鉴自Alice的书籍

构建

codd是用Rust编写的。您可以使用Rust 1.46.0或更高版本来构建库

git clone https://github.com/salmans/codd.git
cd codd
cargo build

示例: 音乐

在Cargo.toml中将codd添加到您的项目依赖项

[dependencies]
codd = "0.1"

在您的代码中使用codd

use codd::{Database, Error, Expression};

创建一个新的数据库

    let mut music = Database::new(); // music database

将关系添加到数据库中

    // `musician`, `band` and `song` are `Relation` expressions.
    let musician = music.add_relation("musician")?;
    let band = music.add_relation("band")?;
    let song = music.add_relation("song")?;

向您的数据库关系中插入元组(记录)

    music.insert(
        &musician,
        vec![
            Musician {
                name: "John Petrucci".into(),
                band: Some("Dream Theater".into()),
                instruments: vec![Guitar],
            },
            Musician {
                name: "Taylor Swift".into(),
                band: None,
                instruments: vec![Vocals],
            },
            // more tuples...
        ]
        .into(),
    )?;
    
    // add tuples to other relations...

构造查询表达式并在数据库中评估它们


    let guitarist_name = musician
        .builder()
        .select(|m| m.instruments.contains(&Guitar))
        .project(|g| g.name.to_string())
        .build();

    assert_eq!(
        vec![
            "Alex Turner".to_string(),
            "Conor Mason".into(),
            "John Petrucci".into(),
        ],
        music.evaluate(&guitarist_name)?.into_tuples() // evaluate the query and get the results
    );

这是一个更复杂的查询

    let dt_member = musician
        .builder()
        .with_key(|m| m.band.clone())
            // use `band` as the join key for `musician`
        .join(band.builder().with_key(|b| Some(b.name.clone()))) 
            // join with `band` with `name` as the join key
        .on(|_, m, b| (m.name.to_string(), b.name.to_string()))
            // combine tuples of `musician` and `band` in a new relation
        .select(|m| m.1 == "Dream Theater")
        .project(|m| m.0.to_string())
        .build();

    assert_eq!(
        vec!["John Petrucci".to_string(), "Jordan Rudess".into()],
        music.evaluate(&dt_member)?.into_tuples()
    );

存储表达式的视图

    let dt_member_view = music.store_view(dt_members)?; // view on `dt_member`
    let drummer_view = music.store_view(                // drummers view
        musician
            .builder()
            .select(|m| m.instruments.contains(&Drums))
            .build(),
    )?;

    // inserting more tuples:
    music.insert(
        &musician,
        vec![
            Musician {
                name: "John Myung".into(),
                band: Some("Dream Theater".into()),
                instruments: vec![Guitar],
            },
            Musician {
                name: "Mike Mangini".into(),
                band: Some("Dream Theater".into()),
                instruments: vec![Drums],
            },
        ]
        .into(),
    )?;

    // views are up-to-date:
    assert_eq!(
        vec![
            Musician {
                name: "Lars Ulrich".into(),
                band: Some("Metallica".into()),
                instruments: vec![Drums]
            },
            Musician {
                name: "Mike Mangini".into(),
                band: Some("Dream Theater".into()),
                instruments: vec![Drums]
            }
        ],
        music.evaluate(&drummer_view)?.into_tuples()
    );
    assert_eq!(
        vec![
            "John Myung".to_string(),
            "John Petrucci".into(),
            "Jordan Rudess".into(),
            "Mike Mangini".into()
        ],
        music.evaluate(&dt_member_view)?.into_tuples()
    );

    Ok(())
}

依赖项

~315–790KB
~18K SLoC