20个不稳定版本 (3个重大更改)

0.4.5 2024年4月5日
0.4.4 2024年3月17日
0.3.3 2024年3月11日
0.2.3 2024年3月8日
0.1.5 2024年3月8日

#280数据库接口

Download history 3/week @ 2024-05-22 224/week @ 2024-07-24 51/week @ 2024-07-31

每月下载量 275

MIT 许可证

59KB
772

NanoDB

NanoDB是一个简单、轻量级、易于使用的Rust JSON数据库。它旨在用于不需要完整数据库的小型到中型项目。它提供了一种简单易用的API来读取和写入JSON数据。NanoDB提供了以下功能

  • 简单API:易于操作的JSON数据接口。
  • 原子操作:通过原子读取和写入保证数据一致性。
  • 树结构:支持使用专用树进行针对性和修改。
  • 异步I/O:通过非阻塞I/O提高性能。
  • 线程安全:适用于多线程使用。

NanoDB区分了三种专门的树类型,每种类型都设计用于在不同的环境中高效、安全地与JSON数据交互。

  • :该结构封装了原始JSON数据的克隆子树。这个克隆表示原始数据的一个特定部分,由JSON结构中的指定路径指向。这使能够针对数据的一个离散部分进行操作,而不会影响数据库中的其余数据。如果需要,NanoDB允许将树合并回主数据库。
  • ReadGuardedTree:基于基本的Tree结构,ReadGuardedTree包括一个读取锁机制。这种增强允许多个线程同时进行并发读取操作,同时保证在这些操作期间数据保持不变。该机制允许存在多个ReadGuardedTree,只要它们只用于读取,从而确保数据一致性而不会阻碍访问性。
  • WriteGuardedTree:类似于ReadGuardedTree,但有一个关键的区别:它具有写入锁以方便原子写入操作。这个排他性锁确保在任何给定时间只有一个WriteGuardedTree可以执行写入操作,从而防止可能导致数据不一致或竞争条件的并发修改。这种严格的控制机制对于在更新时保持数据库的完整性至关重要。

这些专门的树结构是NanoDB设计的基础,使并发数据访问和修改安全之间达到平衡。通过为每种树类型明确划分角色和访问控制,NanoDB确保了在读取密集型或写入密集型场景下数据的完整性和一致性。

示例

查看示例文件夹以获取更多信息。

use nanodb::{error::NanoDBError, nanodb::NanoDB, trees::tree::Tree};
use serde::Deserialize;
use serde_json::{json, Map, Value};
//...

#[derive(Deserialize)]
pub struct MyStruct {
    name: String,
    versions: Vec<f64>,
}

let json_data = r#"{
		"key1": "Welcome!",
		"key2": 42,
		"key3": {
			"name": "NanoDB",
			"versions": [1.0, 2.0, 3.0]
		},
		"key4": [1, 2, 3],
		"key5": ["Welcome", "to", "NanoDB"]
	}"#;

let mut db = NanoDB::new_from("examples/data/data2.json", json_data).unwrap();

// Basic reads (working with cloned sub-tree)
let text: String = db.data().await.get("key1")?.into()?;
let number: i64 = db.data().await.get("key2")?.into()?;
let object: MyStruct = db.data().await.get("key3")?.into()?;
let array: Vec<i64> = db.data().await.get("key4")?.into()?;

// Basic inserts
db.insert("age", 42).await?; // shorthand for db.update().await.insert("age", 42)?;
db.insert("crates", vec!["tokio", "serde"]).await?;
db.insert("some_map", Map::new()).await?;
db.insert("person", json!({"name": "Donald"})).await?;
db.write().await?; // write to file if needed

// Atomic CRUD operations and advanced data manipulation
db.update().await.remove("age")?;
db.update().await.get("key3")?.insert("key", "value")?;
db.update().await.get("key3")?.get("versions")?.push(42.0)?;
db.update().await.get("key4")?.for_each(|v| {
	*v = Value::from(v.as_i64().unwrap() * 2i64);
})?;
db.write().await?; // write to file if needed

// Atomic reader (read() returns a read lock on the db)
let versions: Vec<String> = db.read().await.get("key5")?.into()?;
let number: i64 = db.read().await.get("key4")?.at(0)?.into()?;

// Tree methods and merging
let mut my_tree: Tree = db.data().await.get("key3")?;
my_tree.insert("language", "Rust")?;
db.insert_tree(my_tree).await?;
db.write().await?;

// Advanced write locks
let mut write_lock = db.update().await;
write_lock.insert("key1", "Welcome to NanoDB")?;
write_lock.insert("key1", "Welcome to NanoDB again")?;
write_lock.release_lock(); // release the lock manually to avoid deadlocks
let mut another_write_lock = db.update().await;
assert_eq!(
	another_write_lock.get("key1")?.into::<String>().unwrap(),
	"Welcome to NanoDB again"
);

贡献

欢迎并鼓励贡献!贡献形式多样。您可以

  1. 提交一个功能请求或错误报告作为问题
  2. 问题的形式请求改进文档。
  3. 请求帮助,请查看寻求帮助的问题
  4. 提出任何问题,请查看提问的问题

依赖项

~4–15MB
~184K SLoC