| Crates.io | noatun |
| lib.rs | noatun |
| version | 0.1.2 |
| created_at | 2025-10-09 17:28:54.09151+00 |
| updated_at | 2025-10-12 18:28:14.241767+00 |
| description | Noatun is an in-process, distributed database with materialized view support. |
| homepage | |
| repository | https://github.com/avl/noatun |
| max_upload_size | |
| id | 1875965 |
| size | 2,300,999 |
Welcome to Noatun!
Noatun is an in-process, multi master, distributed database with automatic garbage collection and a materialized view support, written in 100% Rust. Noatun currently supports linux.
Using Noatun:
Noatun properties:
Resources:
See "db_bench"-subfolder for more information. As always, do your own benchmarking, your mileage may vary. This benchmark compares Noatun with sqlite. Suggestions for other products to benchmark against are welcome!
Writes:
Queries:
Noatun write speed is expected to be similar to Sqlite, because a similar amount of work needs to be performed. Noatun write speed will be reduced with more complex materialization rules. Sqlite write performance is affected by the complexity of indices.
For simple queries in a moderately sized database, Noatun will likely always be significantly faster than Sqlite. The reason is that noatun queries are written in rust, and operate directly on memory-mapped RAM. For complex queries, sqlite query optimizer may give it the edge.
The folder examples contains several examples. examples/issue_tracker.rs contains a ratatui-based
issue tracker.
Check the examples-folder for examples that feature distribution.
// Simple app to show using a noatun db, without any replication
use anyhow::Result;
use noatun::data_types::{NoatunHashMap, NoatunString};
use noatun::database::{DatabaseSettings, OpenMode};
use noatun::{noatun_object, Database, Message, MessageId, Object, SavefileMessageSerializer};
use savefile_derive::Savefile;
use std::pin::Pin;
// Define our database
noatun_object!(
struct ExampleDb {
pod total_salary_cost: u32,
object employees: NoatunHashMap<NoatunString, Employee>,
}
);
// Define the Employee type used in the database
noatun_object!(
#[derive(PartialEq)]
struct Employee {
object name: NoatunString,
pod salary: u32
}
);
// Define our event (in real projects, this would usually be an enum)
#[derive(Savefile, Debug)]
pub struct ExampleMessage {
name: String,
salary: u32,
}
impl Message for ExampleMessage {
type Root = ExampleDb;
type Serializer = SavefileMessageSerializer<Self>;
// Define a rule for applying the message to the database
fn apply(&self, _time: MessageId, root: Pin<&mut Self::Root>) {
let root = root.pin_project();
let new_total_salary = root.total_salary_cost.export() + self.salary;
root.total_salary_cost.set(new_total_salary);
root.employees.insert(
self.name.as_str(),
&EmployeeNative {
name: self.name.clone(),
salary: self.salary,
},
);
}
}
fn main() -> Result<()> {
// Create a new database
let mut db: Database<ExampleMessage> = Database::create_new(
"test/example1.bin",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
// Add some messages
let mut s = db.begin_session_mut()?;
s.append_local(ExampleMessage {
name: "Andersen".to_string(),
salary: 25,
})?;
s.append_local(ExampleMessage {
name: "Smith".to_string(),
salary: 20,
})?;
s.commit()?;
let s = db.begin_session()?;
let mut employees: Vec<_> = s.with_root(|root| {
// Verify total salary is expected value
assert_eq!(root.total_salary_cost.get(), 45);
// Extract the list of employees
root.employees.export().values().cloned().collect()
});
employees.sort_by_key(|emp| emp.name.clone());
// Check that database contains the employees we expect
assert_eq!(
employees,
vec![
EmployeeNative {
name: "Andersen".to_string(),
salary: 25,
},
EmployeeNative {
name: "Smith".to_string(),
salary: 20,
},
]
);
Ok(())
}