Skip to main content

cratestack_rusqlite/value/
bind.rs

1//! `SqlValue` → rusqlite binding adapter.
2//!
3//! TEXT-as-canonical storage for Uuid / DateTime / Json / Decimal. See the
4//! parent module docs for the storage-class map.
5
6use cratestack_core::Value;
7use cratestack_sql::SqlValue;
8use rusqlite::ToSql;
9use rusqlite::types::{ToSqlOutput, ValueRef};
10
11/// Adapter that lets a borrowed `SqlValue` be bound by rusqlite.
12pub struct SqlValueParam<'a>(pub &'a SqlValue);
13
14impl<'a> ToSql for SqlValueParam<'a> {
15    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
16        use rusqlite::types::Value as RV;
17
18        let value: ToSqlOutput<'_> = match self.0 {
19            SqlValue::Bool(v) => ToSqlOutput::Owned(RV::Integer(i64::from(*v))),
20            SqlValue::Int(v) => ToSqlOutput::Owned(RV::Integer(*v)),
21            SqlValue::Float(v) => ToSqlOutput::Owned(RV::Real(*v)),
22            SqlValue::String(v) => ToSqlOutput::Borrowed(ValueRef::Text(v.as_bytes())),
23            SqlValue::Bytes(v) => ToSqlOutput::Borrowed(ValueRef::Blob(v.as_slice())),
24            SqlValue::Uuid(v) => ToSqlOutput::Owned(RV::Text(v.hyphenated().to_string())),
25            SqlValue::DateTime(v) => ToSqlOutput::Owned(RV::Text(format_datetime(v))),
26            SqlValue::Json(v) => ToSqlOutput::Owned(RV::Text(format_json(v))),
27            SqlValue::Decimal(v) => ToSqlOutput::Owned(RV::Text(format_decimal(v))),
28            SqlValue::NullBool
29            | SqlValue::NullInt
30            | SqlValue::NullFloat
31            | SqlValue::NullString
32            | SqlValue::NullBytes
33            | SqlValue::NullUuid
34            | SqlValue::NullDateTime
35            | SqlValue::NullJson
36            | SqlValue::NullDecimal => ToSqlOutput::Owned(RV::Null),
37        };
38        Ok(value)
39    }
40}
41
42fn format_datetime(value: &chrono::DateTime<chrono::Utc>) -> String {
43    value.to_rfc3339_opts(chrono::SecondsFormat::Micros, true)
44}
45
46fn format_json(value: &Value) -> String {
47    serde_json::to_string(value).unwrap_or_else(|_| "null".to_string())
48}
49
50fn format_decimal(value: &cratestack_core::Decimal) -> String {
51    value.to_string()
52}