Expand description
§Redb Model
A derive macro for generating [redb] table definitions and DTO object
conversion methods/implementations.
§Functionality
At a minimum, deriving Model on a named struct will implement the Model
trait, declaring redb::TableDefinition as an associated constant.
#[derive(Model)]
struct User {
#[entry(position = "key")]
id: u32,
#[entry(position = "value")]
name: String,
#[entry(position = "value")]
email: String,
}
// redb::TableDefinition::<u32, (String, String)>
assert_eq!(User::DEFINITION.name(), "User");In the example below, the table name is specified as “outbound_edge”, and the
label field is declared as &str, rather than String in the table. The
impl_ext argument on the struct generates an implementation of ModelExt,
giving access to methods for type conversion between the DTO types and those
of the redb key/value. In this case, calling any of the as_ methods will
Copy the u32 fields, and borrow the String field as a &str.
#[derive(Model, Debug, PartialEq, Eq)]
#[model(name = "outbound_edge", impl_ext)]
struct Edge {
#[entry(position = "key")]
source: u32,
#[entry(position = "key")]
target: u32,
#[entry(position = "value", redb_type = "&str")]
label: String,
}
// redb::TableDefinition::<(u32, u32), &str>
assert_eq!(Edge::DEFINITION.name(), "outbound_edge");
let edge0 = Edge {
source: 0,
target: 1,
label: String::from("label"),
};
let txn = db.begin_write().unwrap();
{
// Model::DEFINITION
let mut table = txn.open_table(Edge::DEFINITION).unwrap();
// ModelExt::as_key_and_value
let (k, v) = edge0.as_key_and_value();
table.insert(k, v).unwrap();
}
txn.commit().unwrap();
// ModelExt::as_key
let k = edge0.as_key();
let txn = db.begin_read().unwrap();
// Model::DEFINITION
let table = txn.open_table(Edge::DEFINITION).unwrap();
let edge1 = table
.get(k)
.unwrap()
// ModelExt::from_key_and_guard
.map(|guard| Edge::from_key_and_guard((k, &guard)))
.unwrap();
assert_eq!(edge0, edge1);§Struct Attributes
A model can be customized with the model attribute, providing any of the
following arguments:
| Argument | Description | Type | Default |
|---|---|---|---|
table_name | The table name passed to the definition | Literal | <struct name> (case-sensitive) |
table_type | Table type, either table or multimap | Literal | table |
impl_ext | Implement ModelExt for the type | bool | false |
impl_from | Implement From<T>, mapping T to ModelExt::from_values(T) and ModelExt::from_guards(T). | bool | false |
Note that impl_from uses methods of impl_ext and therefore requires both
arguments to be specified.
§Field Attributes
Values can be customized with the entry attribute. Each field must specify
position as key or value, and (optionally) provide an alternate redb_type.
When generating a ModelExt definition (providing impl_ext as a struct argument),
from and into operations may need to be explicit. Note that composite
variables (multiple key or value fields) are combined as tuples in the order
they are defined.
| Argument | Description | Type | Default |
|---|---|---|---|
position | The position of the field in an entry, either a key or a value. | enum (key or value) | None |
redb_type | The type defined in the redb::TableDefinition or redb::MultimapTableDefinition. | Type | Field Type |
from | The operation to convert from the redb_type. | Expression | See [Type Conversion] below. |
into | The operation to convert into the redb_type. | Expression | See [Type Conversion] below. |
§Features
The following features can be enabled to handle type conversion for their respective
Type(s). Note that the attributes below can be overwritten by explicit field
attributes.
| Feature | DTO Type | Database Type | From operation | Into operation |
|---|---|---|---|---|
uuid | Uuid | [u8; 16] | Uuid::from_bytes(field) | field.as_bytes() |
secrecy | SecretString | &str | SecretString::from(field) | ExposeSecret::expose_secret(field) |
secrecy | SecretBox<S> | S | SecretBox::new(Box::new(field)) | *ExposeSecret::expose_secret(field) |
use uuid::Uuid;
use secrecy::{SecretString, SecretBox, ExposeSecret};
#[derive(Model)]
#[model(impl_ext)]
struct SecretModel {
#[entry(position = "key")]
id: Uuid,
#[entry(position = "value")]
secret_string: SecretString,
#[entry(position = "value")]
secret_box_1: SecretBox<u32>,
// Set a custom `into` operation.
#[entry(position = "value", into = "secret_box_2.expose_secret() + 1")]
secret_box_2: SecretBox<u32>,
}§Type Conversion
The following is applicable for types not enabled by features:
Conversion from a redb value has the following default behavior (impl_ext only):
- If no
redb_typeis specified, the value is assumed to implementCopyand passed directly to the DTO. - If the specified
redb_typeis a reference (is prefixed by&),to_ownedis called on the value. - If the specified
redb_typeis not a reference,intois called on the value.
Conversion into a redb value takes a type reference, and has the following default behavior (impl_ext only):
- If no
redb_typeis specified, the value is assumed to implementCopyand dereferenced. - If the specified
redb_typeis a reference (is prefixed by&), the value is passed as a reference. - If the specified
redb_typeis not a reference,intois called on the value.
For user defined types, typically implementing From<RedbType> for FieldType and
Into<RedbType> for &FieldType will satisfy type conversion.
#[derive(Copy, Clone)]
struct Wrapper(u32);
// Default `from` operation for `Wrapper`.
impl From<u32> for Wrapper {
fn from(value: u32) -> Self {
Wrapper(value)
}
}
// Default `into` operation for `&Wrapper`.
impl Into<u32> for &Wrapper {
fn into(self) -> u32 {
self.0
}
}
#[derive(Model)]
#[model(impl_ext)]
struct MyModel {
#[entry(position = "key", redb_type = "u32")]
key3: Wrapper
}For external types where a newtype wrapper is not desired, or where the type
does not implement Copy, the from and into operations must be explicit.
Both the from and into argument accept a variable named after the field. For
from expressions, this argument is the redb_type, while for into expressions,
this is a reference of the field value. Note that while the operations are
named from and into, there is no constraint on what operations can be used,
as is demonstrated below where type conversion for Uuid and SecretString
are manually implemented.
use secrecy::{ExposeSecret, SecretString};
use uuid::Uuid;
#[derive(Model)]
#[model(impl_ext)]
struct SecretModel {
#[entry(
position = "key",
redb_type = "[u8; 16]",
from = "Uuid::from_bytes(id)", // `id` is `[u8; 16]`.
into = "id.into_bytes()" // `id` is `&Uuid`.
)]
id: Uuid,
#[entry(
position = "value",
redb_type = "&str",
from = "SecretString::from(secret)", // `secret` is `&str`.
into = "secret.expose_secret()" // `secret` is `&SecretString`.
)]
secret: SecretString,
}§Type Aliases
Generated definitions of the ModelExt traits defines type aliases for the
common key and value tuples used extensively in generated code. These may be
useful for extending the functionality of models without explicitly stating
key/value types.
| Alias | Description |
|---|---|
ModelExt::RedbKey | The K argument for the given redb definition. |
ModelExt::RedbValue | The V argument for the given redb definition. |
ModelExt::ModelKey | A tuple of the owned key type(s) defined in the model. |
ModelExt::ModelValue | A tuple of the owned value type(s) defined in the model. |
§Compatability
redb | redb_model |
|---|---|
3 | 0.12 |
2 | 0.1-0.11 |
Traits§
- Model
- Trait for table definition.
- Model
Ext - Conversion methods for a
Modeland the associated keys and values.