8 releases (4 breaking)
0.5.2 | Apr 25, 2020 |
---|---|
0.5.1 | Sep 5, 2019 |
0.5.0 | Aug 21, 2019 |
0.4.0 | Aug 1, 2019 |
0.1.0 | Apr 16, 2019 |
#2688 in Database interfaces
35 downloads per month
37KB
927 lines
Description
rql
is an in-memory pseudo database for Rust. It provides functionality for managing pseudo-relational tables and their schema.
For more information, check out the documentation.
lib.rs
:
Description
RQL (Rusty Query Language) is a library design to bring sql-like logic to Rust. However, bear in mind that there is no traditional database here, just some traits and adapters applied to iterators and hashmaps.
Important Note
rql
does not provide a real database. All data is stored in memory. This
pseudo-database can be saved to and loaded from the disk via serialization and
deserialization from serde
. A number of serialization protocols are supported
so that you may choose one to suit your speed, size, and backward-compatibility
needs.
Schema
To use an rql
database, you must first define some schema. Every table is defined
by a struct representing a single entry. In this example, we will define three tables:
User, Group, and Member.
use rql::prelude::*;
#[derive(Serialize, Deserialize)]
struct User {
name: String,
age: u8,
}
#[derive(Serialize, Deserialize)]
struct Group {
name: String,
}
#[derive(Serialize, Deserialize)]
struct Member {
user_id: Id<User>,
group_id: Id<Group>,
permission: bool,
}
Unique id fields are not necessary, as every entry is automatically
given a unique identifier. References to entries in other tables
are denoted with Id<T>
.
To make the actual schema, use the schema!
macro:
schema! {
MySchema {
user: User,
group: Group,
member: Member,
}
}
Database operations
Below are a few simple ways of interfacing with the database.
// Create a new database with the previously defined schema
// We pass a folder name for the database files as well as a representation type
let db = MySchema::new("test_database_example", HumanReadable).unwrap();
// Insert values into the database
// Insertion returns the new row's id
let dan = db.user_mut().insert(User { name: "Dan".into(), age: 25 });
let steve = db.user_mut().insert(User { name: "Steve".into(), age: 39 });
let mary = db.user_mut().insert(User { name: "Mary".into(), age: 31 });
let admin = db.group_mut().insert(Group { name: "Admin".into() });
let normal = db.group_mut().insert(Group { name: "Normal User".into() });
db.member_mut().insert(Member { user_id: dan, group_id: admin, permission: true });
db.member_mut().insert(Member { user_id: steve, group_id: normal, permission: true });
db.member_mut().insert(Member { user_id: mary, group_id: normal, permission: false });
// Data can easily be looked up by id
db.user_mut().get_mut(dan).unwrap().age += 1;
let dan_age = db.user().get(dan).unwrap().age;
assert_eq!(dan_age, 26);
// Data can be selected from a table
let ages: Vec<u8> = db.user().select(|user| user.age).collect();
// Use `wher` to filter entries
let can_run_for_president: Vec<String> =
db.user()
.wher(|user| user.age >= 35)
.select(|user| user.name.clone())
.collect();
// Table intersections are done using `relate`
// A function relating the tables is required
for (user, permission) in db.user()
.relate(
&*db.member(),
|user, member| user.id == member.user_id && member.group_id == normal
)
.select(|(user, member)| (&user.data.name, member.permission)) {
println!("{} is a normal user with permission = {}", user, permission);
}
// Rows can be updated with `update`
for mut user in db.user_mut().update() {
user.age += 1;
}
// Rows can be deleted in a few ways
// By id
db.user_mut().delete_one(steve);
// With a where clause
db.member_mut().delete_where(|member| member.permission);
// With an iterator over ids
db.user_mut().delete_iter(|_| vec![dan, mary]);
// Changes to the database are automatically saved, so they can be loaded again
let db_copy = MySchema::new("test_database_example", HumanReadable).unwrap();
assert_eq!(db.user().len(), db_copy.user().len() );
assert_eq!(db.group().len(), db_copy.group().len() );
assert_eq!(db.member().len(), db_copy.member().len());
Dependencies
~3–4MB
~81K SLoC