2 个版本
0.1.1 | 2021 年 5 月 1 日 |
---|---|
0.1.0 | 2021 年 4 月 27 日 |
#2137 在 数据库接口
115KB
2K SLoC
MemQuery
MemQuery 是一个简单的库,用于创建、查询和更新以 JSON 对象表示的内存文档,并使用类似 MongoDB 的操作进行查询。
这不是一个数据库,也不是试图进行任何优化。它是为了单元测试或需要小型内存文档存储的简单项目而设计的。
该库使用支持 tokio 的异步 API。该库还有一个同步 API,可以通过 sync
功能标志启用。
示例用法
创建数据库
use memquery::{doc, errors::Error, memdb::MemDb, query};
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
创建集合
memdb.create_collection("TestCollection").await;
获取集合句柄
let coll = memdb.collection("TestCollection").await?;
插入文档
coll.insert(doc!({ "name": "Tom", "age": 25 })).await?;
查找文档
let docs = coll.find(query!({"name": "Tom", "age": 25})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["name"], "Tom");
逻辑查询操作符
$and
let docs = coll
.find(query!({ "$and": [{ "name": "Bob" }, { "age": 20 }] }))
.await?;
$or
let docs = coll
.find(query!({ "$or": [{ "name": "Bob" }, { "age": 30 }] }))
.await?;
比较查询操作符
$eq
按字段比较
let docs = coll.find(query!({ "qty": { "$eq": 20 } })).await?;
在嵌入式文档中比较
let docs = coll.find(query!({ "item.name": { "$eq": "ab" } })).await?;
您还可以比较数组与嵌入式数组
coll
.insert(doc!({ "item": { "name": "ab", "code": "123" }, "qty": 15, "tags": [ "A", "B", "C" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "cd", "code": "123" }, "qty": 20, "tags": [ "B" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "ij", "code": "456" }, "qty": 25, "tags": [ "A", "B" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "xy", "code": "456" }, "qty": 30, "tags": [ "B", "A" ] }))
.await?;
coll
.insert(
doc!({ "item": { "name": "mn", "code": "000" }, "qty": 20, "tags": [ [ "A", "B" ], "C" ] }),
)
.await?;
let docs = coll
.find(query!({ "tags": { "$eq": [ "A", "B" ] } }))
.await?;
assert_eq!(docs.len(), 2);
assert_eq!(docs[0]["item"]["name"], "ij");
assert_eq!(docs[1]["item"]["name"], "mn");
或嵌入式数组中的值
coll
.insert(doc!({ "item": { "name": "ab", "code": "123" }, "qty": 15, "tags": [ "A", "B", "C" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "cd", "code": "123" }, "qty": 20, "tags": [ "B" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "ij", "code": "456" }, "qty": 25, "tags": [ "A", "B" ] }))
.await?;
coll
.insert(doc!({ "item": { "name": "xy", "code": "456" }, "qty": 30, "tags": [ "B", "A" ] }))
.await?;
coll
.insert(
doc!({ "item": { "name": "mn", "code": "000" }, "qty": 20, "tags": [ [ "A", "B" ], "C" ] }),
)
.await?;
let docs = coll.find(query!({ "tags": { "$eq": "B" } })).await?;
assert_eq!(docs.len(), 4);
assert_eq!(docs[0]["item"]["name"], "ab");
assert_eq!(docs[1]["item"]["name"], "cd");
assert_eq!(docs[2]["item"]["name"], "ij");
assert_eq!(docs[3]["item"]["name"], "xy");
$gt
let docs = coll.find(query!({ "qty": { "$gt": 20 } })).await?;
$gte
let docs = coll.find(query!({ "qty": { "$gte": 20 } })).await?;
$lt
let docs = coll.find(query!({ "qty": { "$lt": 20 } })).await?;
$lte
let docs = coll.find(query!({ "qty": { "$lte": 20 } })).await?;
查找所有文档
let docs = coll.find(query!({})).await?;
更新文档
这显示了如何使用 find_and_update
API 的示例。
通过替换整个文档来更新文档
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs_updated = coll
.find_and_update(
query!({"name": "Bob"}),
update!({"nickname": "Bobcat", "voice": "meow"}),
)
.await?;
assert_eq!(docs_updated, 1);
let docs = coll.find(query!({"nickname": "Bobcat"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["voice"], "meow");
更新文档中的特定字段
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs_updated = coll
.find_and_update(
query!({"name": "Bob"}),
update!({"$set": { "name": "Roy", "age": 21, "email": "[email protected]"}}),
)
.await?;
assert_eq!(docs_updated, 1);
let docs = coll.find(query!({"name": "Roy"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["age"], 21);
assert_eq!(docs[0]["email"], "[email protected]");
更新文档以删除字段
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs_updated = coll
.find_and_update(
query!({ "name": "Bob" }),
update!({ "$set": { "name": "Roy", "age": 21, "email": "[email protected]" }}),
)
.await?;
assert_eq!(docs_updated, 1);
let docs = coll.find(query!({"name": "Roy"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["age"], 21);
assert_eq!(docs[0]["email"], "[email protected]");
let docs_updated2 = coll
.find_and_update(
query!({ "name": "Roy" }),
update!({ "$unset": { "email": "" }}),
)
.await?;
assert_eq!(docs_updated2, 1);
let docs = coll.find(query!({"name": "Roy"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["age"], 21);
assert_eq!(docs[0]["email"], serde_json::Value::Null);
增加文档中字段的值
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs_updated = coll
.find_and_update(query!({"name": "Bob"}), update!({"$inc": { "age": -5 }}))
.await?;
assert_eq!(docs_updated, 1);
let docs = coll.find(query!({"name": "Bob"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["age"], 15.0);
乘以文档中字段的值
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs_updated = coll
.find_and_update(query!({"name": "Bob"}), update!({"$mul": { "age": 5}}))
.await?;
assert_eq!(docs_updated, 1);
let docs = coll.find(query!({"name": "Bob"})).await?;
assert_eq!(docs.len(), 1);
assert_eq!(docs[0]["age"], 100.0);
删除文档
let memdb = MemDb::new();
memdb.create_collection("TestCollection").await;
let coll = memdb.collection("TestCollection").await?;
coll.insert(doc!({ "name": "Rob", "age": 25 })).await?;
coll.insert(doc!({ "name": "Bob", "age": 20 })).await?;
coll.insert(doc!({ "name": "Tom", "age": 30 })).await?;
let docs = coll.find_and_delete(query!({})).await?;
assert_eq!(docs.len(), 3);
let docs_remaining = coll.find(query!({})).await?;
assert_eq!(docs_remaining.len(), 0);
同步 API
要使用同步 API,您需要通过 sync
功能标志启用它。
use memquery::{doc, errors::Error, query, sync_memdb::MemDb};
let memdb = MemDb::new();
memdb.create_collection("TestCollection");
let coll = memdb.collection("TestCollection")?;
coll.insert(
doc!({ "item": { "name": "ab", "code": 123 }, "qty": 15, "tags": [ "A", "B", "C" ] }),
)?;
coll.insert(doc!({ "item": { "name": "cd", "code": 123 }, "qty": 20, "tags": [ "B" ] }))?;
coll.insert(doc!({ "item": { "name": "ij", "code": 456 }, "qty": 25, "tags": [ "A", "B" ] }))?;
coll.insert(doc!({ "item": { "name": "xy", "code": 456 }, "qty": 30, "tags": [ "B", "A" ] }))?;
coll.insert(
doc!({ "item": { "name": "mn", "code": 000 }, "qty": 20, "tags": [ [ "A", "B" ], "C" ] }),
)?;
let docs = coll.find(query!({ "item.code": { "$lte": 123 } }))?;
assert_eq!(docs.len(), 3);
assert_eq!(docs[0]["item"]["name"], "ab");
assert_eq!(docs[1]["item"]["name"], "cd");
assert_eq!(docs[2]["item"]["name"], "mn");
构建和运行测试
构建 Rust 库
要构建库
- cargo build
测试 Rust 库
要测试异步 API
- cargo t
要测试同步 API
- cargo t --features "sync"
构建 WASM (wsmemquery.wasm)
添加 wasm32-unknown-unknown 目标
- rustup target add wasm32-unknown-unknown
将 memquery 构建为 WebAssembly
- cd wasm
- cargo build --target wasm32-unknown-unknown
依赖项
~3–11MB
~98K SLoC