1个不稳定版本
0.1.0 | 2020年11月1日 |
---|
#274 在 数据库实现
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