sea-query-spanner 0.1.0

Spanner SQL dialect for sea-query
Documentation
use sea_query::Value;

pub fn value_to_spanner_literal(value: &Value) -> String {
    match value {
        Value::Bool(Some(b)) => if *b { "TRUE" } else { "FALSE" }.to_string(),
        Value::Bool(None) => "NULL".to_string(),
        Value::TinyInt(Some(i)) => i.to_string(),
        Value::TinyInt(None) => "NULL".to_string(),
        Value::SmallInt(Some(i)) => i.to_string(),
        Value::SmallInt(None) => "NULL".to_string(),
        Value::Int(Some(i)) => i.to_string(),
        Value::Int(None) => "NULL".to_string(),
        Value::BigInt(Some(i)) => i.to_string(),
        Value::BigInt(None) => "NULL".to_string(),
        Value::TinyUnsigned(Some(i)) => i.to_string(),
        Value::TinyUnsigned(None) => "NULL".to_string(),
        Value::SmallUnsigned(Some(i)) => i.to_string(),
        Value::SmallUnsigned(None) => "NULL".to_string(),
        Value::Unsigned(Some(i)) => i.to_string(),
        Value::Unsigned(None) => "NULL".to_string(),
        Value::BigUnsigned(Some(i)) => i.to_string(),
        Value::BigUnsigned(None) => "NULL".to_string(),
        Value::Float(Some(f)) => format!("{:.}", f),
        Value::Float(None) => "NULL".to_string(),
        Value::Double(Some(d)) => format!("{:.}", d),
        Value::Double(None) => "NULL".to_string(),
        Value::String(Some(s)) => escape_string(s),
        Value::String(None) => "NULL".to_string(),
        Value::Char(Some(c)) => escape_string(&c.to_string()),
        Value::Char(None) => "NULL".to_string(),
        Value::Bytes(Some(b)) => format!("B\"{}\"", bytes_to_hex(b)),
        Value::Bytes(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDate(Some(d)) => format!("DATE '{}'", d.format("%Y-%m-%d")),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDate(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoTime(Some(t)) => format!("'{}'", t.format("%H:%M:%S%.f")),
        #[cfg(feature = "with-chrono")]
        Value::ChronoTime(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTime(Some(dt)) => {
            format!("TIMESTAMP '{}'", dt.format("%Y-%m-%dT%H:%M:%S%.fZ"))
        }
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTime(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeUtc(Some(dt)) => {
            format!("TIMESTAMP '{}'", dt.format("%Y-%m-%dT%H:%M:%S%.fZ"))
        }
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeUtc(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeLocal(Some(dt)) => {
            format!("TIMESTAMP '{}'", dt.format("%Y-%m-%dT%H:%M:%S%.fZ"))
        }
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeLocal(None) => "NULL".to_string(),
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeWithTimeZone(Some(dt)) => {
            format!("TIMESTAMP '{}'", dt.format("%Y-%m-%dT%H:%M:%S%.fZ"))
        }
        #[cfg(feature = "with-chrono")]
        Value::ChronoDateTimeWithTimeZone(None) => "NULL".to_string(),
        #[cfg(feature = "with-uuid")]
        Value::Uuid(Some(u)) => format!("'{}'", u.hyphenated()),
        #[cfg(feature = "with-uuid")]
        Value::Uuid(None) => "NULL".to_string(),
        #[cfg(feature = "with-json")]
        Value::Json(Some(j)) => escape_string(&j.to_string()),
        #[cfg(feature = "with-json")]
        Value::Json(None) => "NULL".to_string(),
        #[cfg(feature = "with-rust_decimal")]
        Value::Decimal(Some(d)) => d.to_string(),
        #[cfg(feature = "with-rust_decimal")]
        Value::Decimal(None) => "NULL".to_string(),
        Value::Array(_, Some(values)) => {
            let elements: Vec<String> = values.iter().map(value_to_spanner_literal).collect();
            format!("[{}]", elements.join(", "))
        }
        Value::Array(_, None) => "NULL".to_string(),
        #[allow(unreachable_patterns)]
        _ => "NULL".to_string(),
    }
}

fn escape_string(s: &str) -> String {
    format!("'{}'", s.replace('\'', "''").replace('\\', "\\\\"))
}

fn bytes_to_hex(bytes: &[u8]) -> String {
    bytes.iter().map(|b| format!("{:02x}", b)).collect()
}