dinoco_engine 2.0.5

Database adapters, query execution, and migration engine components for Dinoco.
Documentation
use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
use serde_json::Value;

/// Reconstructs a row-model struct from a single JSON object.
///
/// Generated by `#[derive(Entity)]`/`#[derive(EntityExtend)]` for every
/// entity and projection, this is what lets [`crate::Backend`] decode the
/// combined result of a `find_batch(...)` call: each sub-query's rows are
/// aggregated into a JSON array by the database itself (`json_build_object`
/// on Postgres, `JSON_OBJECT` on MySQL, `json_object` on SQLite), and every
/// element of that array is turned back into a typed row through this trait
/// instead of a native driver row.
pub trait DinocoJson: Sized + Send + Sync + 'static {
    fn from_json_row(value: &Value) -> Option<Self>;
}

/// Parses a JSON-aggregated datetime column.
///
/// Postgres/SQLite emit RFC 3339 text for `timestamptz`/ISO-stored columns;
/// MySQL's `JSON_OBJECT` renders `DATETIME` values as `"YYYY-MM-DD
/// HH:MM:SS[.ffffff]"` with no offset, which is treated as UTC (matching how
/// `DateTime<Utc>` columns are already stored on that backend).
pub fn datetime_from_json(value: &Value) -> Option<DateTime<Utc>> {
    let text = value.as_str()?;

    if let Ok(value) = DateTime::parse_from_rfc3339(text) {
        return Some(value.with_timezone(&Utc));
    }

    for format in ["%Y-%m-%d %H:%M:%S%.f", "%Y-%m-%dT%H:%M:%S%.f"] {
        if let Ok(value) = NaiveDateTime::parse_from_str(text, format) {
            return Some(value.and_utc());
        }
    }

    None
}

/// Parses a JSON-aggregated date column (`"YYYY-MM-DD"`, tolerating a
/// timestamp prefix if the column carries more precision than expected).
pub fn naive_date_from_json(value: &Value) -> Option<NaiveDate> {
    let text = value.as_str()?;

    if let Ok(value) = NaiveDate::parse_from_str(text, "%Y-%m-%d") {
        return Some(value);
    }

    text.get(0..10).and_then(|prefix| NaiveDate::parse_from_str(prefix, "%Y-%m-%d").ok())
}