Crate ledb

Source
Expand description

§Lightweight embedded database

§Features

  • Processing documents which implements Serialize and Deserialize traits from serde.
  • Identifying documents using auto-incrementing integer primary keys.
  • Indexing any fields of documents using unique or duplicated keys.
  • Searching and ordering documents using indexed fields or primary key.
  • Selecting documents using complex filters with fields comparing and logical operations.
  • Updating documents using rich set of modifiers.
  • Storing documents into independent storages so called collections.
  • Flexible query! macro which helps write clear and readable queries.
  • Using LMDB as backend for document storage and indexing engine.

§Usage example

use serde::{Serialize, Deserialize};
use serde_json::json;
use ledb::{Storage, Options, IndexKind, KeyType, Filter, Comp, Order, OrderKind, Identifier, Primary, Document, query, query_extr};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Document)]
struct MyDoc {
    // primary key field
    #[document(primary)]
    id: Option<Primary>,
    // unique key field
    #[document(unique)]
    title: String,
    // key field
    #[document(index)]
    tag: Vec<String>,
    timestamp: u32,
}

fn main() {
    let db_path = ".test_dbs/my_temp_db";
    let _ = std::fs::remove_dir_all(&db_path);

    // Open storage
    let storage = Storage::new(&db_path, Options::default()).unwrap();

    // Get collection
    let collection = storage.collection("my-docs").unwrap();

    // Ensure indexes
    query!(index for collection
        title str unique,
        tag str,
        timestamp int unique,
    ).unwrap();

    // Ensure indexes using document type
    query!(index MyDoc for collection).unwrap();

    // Insert JSON document
    let first_id = query!(insert into collection {
        "title": "First title",
        "tag": ["some tag", "other tag"],
        "timestamp": 1234567890,
    }).unwrap();

    // Insert typed document
    let second_id = collection.insert(&MyDoc {
        id: None,
        title: "Second title".into(),
        tag: vec![],
        timestamp: 1234567657,
    }).unwrap();

    // Find documents
    let found_docs = query!(
        find MyDoc in collection
        where title == "First title"
    ).unwrap().collect::<Result<Vec<_>, _>>().unwrap();

    // Update documents
    let n_affected = query!(
        update in collection modify title = "Other title"
        where title == "First title"
    ).unwrap();

    // Find documents with descending ordering
    let found_docs = query!(
        find MyDoc in collection order desc
    ).unwrap().collect::<Result<Vec<_>, _>>().unwrap();

    // Remove documents
    let n_affected = query!(
        remove from collection where title == "Other title"
    ).unwrap();
}

§Field names

Field name is a sequence of dot-separated identifiers which represents nesting of value in document. Also fully qualified field names supports wildcard pattern (*).

For example, in document below:

{
    "a": "abc",
    "b": {
        "c": 11
    },
    "d": [
      "a"
    ],
    "s": [
      { n: 1 },
      { n: 2 }
    ],
    "h": {
      "a": { s: "a" },
      "b": { s: "b" }
    }
}

You can access fields by the next ways:

a == "abc"
a += "def"
b.c > 10
b.c += 3
d == "a"
d[-1..] += ["b", "c"]
s.n > 1
h.*.s == "a"

§Indexing

Index query example:

query!(
    index for some_collection
        some_field Int unique, // unique index
        other_field.with.sub_field String,
        wildcarded.*.sub_field Int,
        // ...next fields
)

§Index kinds

Internal TypeJSON TypeDescription
Index“index”The values can be duplicated
Unique“unique”Each value is unique

Unique index guarantee that each value can be stored once, any duplicates disalowed.

The operation will fail in two cases:

  1. When you try to insert new document which duplicate unique field
  2. When you try to ensure unique index for field which have duplicates

Unique fields is pretty fit for sorting.

TODO: Full-text index kind for searching

§Key types

Internal TypeJSON TypeDescription
Int“int”64-bit signed integers
Float“float”64-bit floating point numbers
Bool“bool”boolean values
String“string”UTF-8 strings
Binary“binary”raw binary data

§Filters

§Comparison operations

Internal ReprJSON ReprQuery (where)Description
Eq(value){“$eq”: value}field == valGeneral Equality
In(Vec){“$in”: […values]}field of […val]One of
Lt(value){“$lt”: value}field < valLess than
Le(value){“$le”: value}field <= valLess than or equal
Gt(value){“$gt”: value}field > valGreater than
Ge(value){“$ge”: value}field >= valGreater than or equal
Bw(a, true, b, true){“$bw”: [a, true, b, true]}field in a..bBetween including a b
Bw(a, false, b, false){“$bw”: [a, false, b, false]}field <in> a..bBetween excluding a b
Bw(a, true, b, false){“$bw”: [a, true, b, false]}field in> a..bBetween incl a excl b
Bw(a, false, b, true){“$bw”: [a, false, b, true]}field <in a..bBetween excl a incl b
Has“$has”field ?Has value (not null)

NOTE: To be able to use particular field of document in filters you need create index for it first.

Some examples:

query!(@filter field == 123)
query!(@filter field.subfield != "abc")
query!(@filter field > 123)
query!(@filter field <= 456)
query!(@filter field of [1, 2, 3])
query!(@filter field in 123..456)   // [123 ... 456]
query!(@filter field <in> 123..456) // (123 ... 456)
query!(@filter field <in 123..456)  // (123 ... 456]
query!(@filter field in> 123..456)  // [123 ... 456)

§Logical operations

Internal ReprJSON ReprQuery (where)Description
Not(Box){“$not”: filter}! filterFilter is false
And(Vec){“$and”: […filters]}filter && …filtersAll filters is true
Or(Vec){“$or”: […filters]}filter || …filtersAny filter is true

NOTE: Be careful with using complex ORs and global NOTs since it may slow down your queries.

Some examples:

// negate filter condition
query!(@filter ! field == "abc")

// and filter conditions
query!(@filter field > 123 && field <= 456)

// or filter conditions
query!(@filter field <= 123 || field > 456)

§Results ordering

Internal ReprJSON ReprQuery (where)Description
Primary(Asc)“$asc”>, asc (default)Ascending ordering by primary key
Primary(Desc)“$desc”<, descDescending ordering by primary key
Field(field, Asc){“field”: “$asc”}field >, field ascAscending ordering by field
Field(field, Desc){“field”: “$desc”}field <, field descDescending ordering by field

Examples:

// ascending ordering by primary key
query!(@order >)
query!(@order asc)

// descending ordering by primary key
query!(@order <)
query!(@order desc)

// ascending ordering by field
query!(@order by field >)
query!(@order by field asc)

// descending ordering by other.field
query!(@order by other.field <)
query!(@order by other.field desc)

§Modifiers

Internal ReprJSON ReprQuery (where)Description
Set(value){“$set”: value}field = valueSet field value
Delete“$delete”field ~Delete field
Add(value){“$add”: value}field += valueAdd value to field
Sub(value){“$sub”: value}field -= valueSubstract value from field
Mul(value){“$mul”: value}field *= valueMultiply field to value
Div(value){“$div”: value}field /= valueDivide field to value
Toggle“$toggle”field !Toggle boolean field
Replace(pat, sub){“$replace”: [“pat”, “sub”]}field ~= “pat” “sub”Replace using regexp
Splice(from, to, Vec){“$splice”: [from, to]}field[from..to] ~Remove from an array
Splice(from, to, Vec){“$splice”: [from, to, …ins]}field[from..to] = insSplice an array
Merge(object){“$merge”: object}field ~= objectMerge an object

The negative range value means position from end of an array:

  • -1 the end of an array
  • -2 the last element
  • -3 the element before the last
  • …and so on

§Extended behavior of modifiers

Internal ReprJSON ReprQuery (where)Description
Add(values){“$add”: […values]}field += [..values]Add unique values to an array as a set
Sub(values){“$sub”: […values]}field -= [..values]Remove unique values to an array as a set
Add(text){“$add”: “text”}field += “text”Append text to a string

Examples:

// set single fields
query!(@modify field = 123)
query!(@modify other.field = "abc")

// set multiple fields
query!(@modify
    field = 1;
    other.field = "abc";
)

// numeric operations
query!(@modify field += 1) // add value to field
query!(@modify field -= 1) // substract value from field
query!(@modify field *= 1) // multiply field to value
query!(@modify field /= 1) // divide field to value

query!(@modify - field) // remove field
query!(@modify ! field) // toggle boolean field

query!(@modify str += "addon") // append piece to string
query!(@modify str ~= "abc" "def") // regexp replace

// modify array as list
query!(@modify list[0..0] = [1, 2, 3]) // prepend to array
query!(@modify list[-1..0] = [1, 2, 3]) // append to array
query!(@modify - list[1..2]) // remove from array
query!(@modify list[1..2] = [1, 2, 3]) // splice array

// modify array as set
query!(@modify set += [1, 2, 3]) // add elements
query!(@modify set -= [4, 5, 6]) // remove elements

// merge an object
query!(@modify obj ~= { a: true, b: "abc", c: 123 })
query!(@modify obj ~= extra)

Re-exports§

pub use ledb_types as types;

Macros§

query
Unified query macro

Structs§

Collection
Collection of documents
DocumentsIterator
Iterator across found documents
Info
Storage info data
KeyField
Indexed field definition
KeyFields
Indexed fields definition
Modify
Modification operator
Options
Database options
RawDocument
Raw document with id representation
Stats
Storage stats data
Storage
Storage of documents
WrappedRegex

Enums§

Action
Modifier action
Comp
Comparison operator of filter
Cond
Condition operator of filter
Error
Database error type
Filter
Filter operator
Identifier
Generic string indentifier
IndexKind
The kind of index
KeyData
The data of key
KeyType
The type of key
Order
Ordering operator
OrderKind
The kind ot order
Value
The Value enum, a loosely typed way of representing any valid CBOR value.

Traits§

Document
Identified document representation
ResultWrap
The helper for converting results with different error types into generic result

Functions§

to_value

Type Aliases§

Primary
Primary key (document identifier)
Result
Database result type

Derive Macros§

Document