Casts
Cast, FromValue, custom types
A model field can be any type that implements both rustique::FromValue (read from a column) and From<T> for rustique::Value (bind as a parameter). This replaces Eloquent’s $casts, accessors and mutators.
Built-in types
Integers, floats, bool, String, Vec<u8>, chrono dates and times, rust_decimal::Decimal, serde_json::Value, and Option<T> of any of them. NULL decodes to None; into a non-Option field it is an Error::Decode (except on Oracle, where NULL into a String is "", since Oracle stores '' as NULL).
#[derive(rustique::Cast)]
// text column: "pending_review", "approved", "gone"
#[derive(Debug, Clone, Copy, Default, PartialEq, rustique::Cast)]
pub enum Status {
#[default]
PendingReview,
Approved,
#[cast(rename = "gone")]
Deleted,
}
// integer column: the discriminant
#[derive(Debug, Clone, Copy, Default, rustique::Cast)]
#[cast(int)]
pub enum Priority { #[default] Low = 1, High = 2 }
// newtype: stored as its inner value
#[derive(Debug, Clone, Default, rustique::Cast)]
pub struct Email(pub String);
// any serde type: stored as JSON
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, rustique::Cast)]
#[cast(json)]
pub struct Settings { pub theme: String, pub beta: bool }
#[rustique::model(table = "users")]
#[derive(Debug, Clone, Default)]
pub struct User {
pub id: i64,
pub status: Status,
pub email: Email,
pub settings: Settings,
pub priority: Option<Priority>,
}
User::query().where_("status", "=", Status::Approved).get(&db).await?; // casts work as bindings tooModel fields need Default (models are built with ..Default::default()), so give cast types a Default.
Hand-written casts
use rustique::{FromValue, Value, ValueError};
pub struct Cents(pub i64);
impl From<Cents> for Value {
fn from(c: Cents) -> Self { Value::I64(c.0) }
}
impl FromValue for Cents {
fn from_value(value: Value) -> Result<Self, ValueError> {
i64::from_value(value).map(Cents)
}
}Override FromValue::from_oracle_null to return a value for Oracle NULLs (as String does with "").
Value
Value is the enum every binding and column passes through: Null, Bool, I64, U64, F64, Decimal, String, Bytes, Date, DateTime, Time, Json. Json holds the document as text: rows keep it unparsed, and it is parsed straight into the field’s type (your #[cast(json)] type, or serde_json::Value). #[cast(json)] writes struct fields in declaration order, so compare Json values as text only when both sides come from the same type. DateTime carries no zone: wall-clock time in UTC, or in the zone set with rustique::set_timezone (see timestamps).