[][src]Crate rql

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());

Re-exports

pub use crate::repr::*;

Modules

example_schema

Example schema generated by the schema! macro

prelude

A prelude for commonly used imports

repr

Ways of serializing/deserializing data

Macros

schema

Macro for generating a schema struct

Structs

Id

An id for indexing rows

OwnedRow

An row of owned data cloned from a Table

Relate

A relationship between two tables

Row

A row in a Table

RowIter

An iterator over rows in a Table

RowIterMut

An mutable iterator over rows in a Table

RowMut

A mutable row in a Table

Select

An adaptor for selecting data

Table

A table abstraction akin to a table in a real schema

TableGuard

An immutable guard to a Table

TableGuardMut

A mutable guard to a Table

Where

A clause for searching through rows and limiting the returned values, similar to a sql WHERE

Enums

Error

An error type for rql

Traits

HasRows

A trait for accessing rows

HasRowsMut

A trait for mutably accessing rows

Idd

A trait for getting row Ids

Type Definitions

Result

A result type for rql