# 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. ```rust #[derive(Model)] struct User { #[entry(position = "key")] id: u32, #[entry(position = "value")] name: String, #[entry(position = "value")] email: String, } // redb::TableDefinition:: 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`. ```rust #[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` | `` (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`, 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 below. `into` | The operation to convert **into** the `redb_type`. | `Expression` | See below. Conversion `from` a `redb` value has the following default behavior (`impl_ext` only): - If no `redb_type` is specified, the value is assumed to implement `Copy` and passed directly to the DTO. - If the specified `redb_type` is a reference (is prefixed by `&`), `to_owned` is called on the value. - If the specified `redb_type` is not a reference, `into` is 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_type` is specified, the value is assumed to implement `Copy` and dereferenced. - If the specified `redb_type` is a reference (is prefixed by `&`), the value is passed as a reference. - If the specified `redb_type` is not a reference, `into` is called on the value. For user defined types, typically implementing `From for FieldType` and `Into for &FieldType` will satisfy type conversion. ```rust #[derive(Copy, Clone)] struct Wrapper(u32); // Default `from` operation for `Wrapper`. impl From for Wrapper { fn from(value: u32) -> Self { Wrapper(value) } } // Default `into` operation for `&Wrapper`. impl Into 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. ```rust 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 the `redb_type` (`[u8; 16]`). into = "id.into_bytes()" // `id` is `&Uuid`. )] id: Uuid, #[entry( position = "value", redb_type = "&str", from = "SecretString::from(secret)", // `secret` is the `redb_type` (`&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. License: MIT OR Apache-2.0