Expand description
§Lightweight embedded database
§Features
- Processing documents which implements
SerializeandDeserializetraits 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 Type | JSON Type | Description |
|---|---|---|
| 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:
- When you try to insert new document which duplicate unique field
- 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 Type | JSON Type | Description |
|---|---|---|
| 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 Repr | JSON Repr | Query (where) | Description |
|---|---|---|---|
| Eq(value) | {“$eq”: value} | field == val | General Equality |
| In(Vec | {“$in”: […values]} | field of […val] | One of |
| Lt(value) | {“$lt”: value} | field < val | Less than |
| Le(value) | {“$le”: value} | field <= val | Less than or equal |
| Gt(value) | {“$gt”: value} | field > val | Greater than |
| Ge(value) | {“$ge”: value} | field >= val | Greater than or equal |
| Bw(a, true, b, true) | {“$bw”: [a, true, b, true]} | field in a..b | Between including a b |
| Bw(a, false, b, false) | {“$bw”: [a, false, b, false]} | field <in> a..b | Between excluding a b |
| Bw(a, true, b, false) | {“$bw”: [a, true, b, false]} | field in> a..b | Between incl a excl b |
| Bw(a, false, b, true) | {“$bw”: [a, false, b, true]} | field <in a..b | Between 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 Repr | JSON Repr | Query (where) | Description |
|---|---|---|---|
| Not(Box | {“$not”: filter} | ! filter | Filter is false |
| And(Vec | {“$and”: […filters]} | filter && …filters | All filters is true |
| Or(Vec | {“$or”: […filters]} | filter || …filters | Any 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 Repr | JSON Repr | Query (where) | Description |
|---|---|---|---|
| Primary(Asc) | “$asc” | >, asc (default) | Ascending ordering by primary key |
| Primary(Desc) | “$desc” | <, desc | Descending ordering by primary key |
| Field(field, Asc) | {“field”: “$asc”} | field >, field asc | Ascending ordering by field |
| Field(field, Desc) | {“field”: “$desc”} | field <, field desc | Descending 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 Repr | JSON Repr | Query (where) | Description |
|---|---|---|---|
| Set(value) | {“$set”: value} | field = value | Set field value |
| Delete | “$delete” | field ~ | Delete field |
| Add(value) | {“$add”: value} | field += value | Add value to field |
| Sub(value) | {“$sub”: value} | field -= value | Substract value from field |
| Mul(value) | {“$mul”: value} | field *= value | Multiply field to value |
| Div(value) | {“$div”: value} | field /= value | Divide 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] = ins | Splice an array |
| Merge(object) | {“$merge”: object} | field ~= object | Merge 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 Repr | JSON Repr | Query (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
- Documents
Iterator - 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
- Wrapped
Regex
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
- Index
Kind - The kind of index
- KeyData
- The data of key
- KeyType
- The type of key
- Order
- Ordering operator
- Order
Kind - The kind ot order
- Value
- The
Valueenum, a loosely typed way of representing any valid CBOR value.
Traits§
- Document
- Identified document representation
- Result
Wrap - The helper for converting results with different error types into generic result