1use apiplant_core::{FieldType, TextCase};
4use sea_orm::sea_query::Value as SqlValue;
5
6pub fn json_to_sql(
12 ty: FieldType,
13 case: Option<TextCase>,
14 v: &serde_json::Value,
15) -> Result<SqlValue, String> {
16 if v.is_null() {
17 return Ok(null_for(ty));
18 }
19 Ok(match ty {
20 FieldType::String | FieldType::Text | FieldType::File => {
21 SqlValue::from(cased(case, v.as_str().ok_or("expected a string")?))
22 }
23 FieldType::Integer => SqlValue::from(
24 i32::try_from(v.as_i64().ok_or("expected an integer")?)
25 .map_err(|_| "integer out of range")?,
26 ),
27 FieldType::BigInt => SqlValue::from(v.as_i64().ok_or("expected an integer")?),
28 FieldType::Float => SqlValue::from(v.as_f64().ok_or("expected a number")?),
29 FieldType::Boolean => SqlValue::from(v.as_bool().ok_or("expected a boolean")?),
30 FieldType::Uuid | FieldType::Reference => {
31 let s = v.as_str().ok_or("expected a UUID string")?;
32 SqlValue::from(uuid::Uuid::parse_str(s).map_err(|e| e.to_string())?)
33 }
34 FieldType::Timestamp => {
35 let s = v.as_str().ok_or("expected an RFC3339 timestamp")?;
36 SqlValue::from(chrono::DateTime::parse_from_rfc3339(s).map_err(|e| e.to_string())?)
37 }
38 FieldType::Json => SqlValue::from(v.clone()),
39 })
40}
41
42fn cased(case: Option<TextCase>, value: &str) -> String {
44 match case {
45 Some(case) => case.apply(value),
46 None => value.to_string(),
47 }
48}
49
50pub fn null_for(ty: FieldType) -> SqlValue {
53 match ty {
54 FieldType::String | FieldType::Text | FieldType::File => SqlValue::String(None),
55 FieldType::Integer => SqlValue::Int(None),
56 FieldType::BigInt => SqlValue::BigInt(None),
57 FieldType::Float => SqlValue::Double(None),
58 FieldType::Boolean => SqlValue::Bool(None),
59 FieldType::Uuid | FieldType::Reference => SqlValue::Uuid(None),
60 FieldType::Timestamp => SqlValue::ChronoDateTimeWithTimeZone(None),
61 FieldType::Json => SqlValue::Json(None),
62 }
63}
64
65pub fn string_to_sql(ty: FieldType, case: Option<TextCase>, s: &str) -> Result<SqlValue, String> {
72 Ok(match ty {
73 FieldType::String | FieldType::Text | FieldType::File => SqlValue::from(cased(case, s)),
74 FieldType::Integer => SqlValue::from(s.parse::<i32>().map_err(|_| "expected an integer")?),
75 FieldType::BigInt => SqlValue::from(s.parse::<i64>().map_err(|_| "expected an integer")?),
76 FieldType::Float => SqlValue::from(s.parse::<f64>().map_err(|_| "expected a number")?),
77 FieldType::Boolean => SqlValue::from(s.parse::<bool>().map_err(|_| "expected a boolean")?),
78 FieldType::Uuid | FieldType::Reference => {
79 SqlValue::from(uuid::Uuid::parse_str(s).map_err(|e| e.to_string())?)
80 }
81 FieldType::Timestamp => {
82 SqlValue::from(chrono::DateTime::parse_from_rfc3339(s).map_err(|e| e.to_string())?)
83 }
84 FieldType::Json => SqlValue::from(serde_json::Value::String(s.to_string())),
85 })
86}
87
88pub fn json_param(v: &serde_json::Value) -> SqlValue {
91 use serde_json::Value as J;
92 match v {
93 J::Null => SqlValue::String(None),
94 J::Bool(b) => SqlValue::from(*b),
95 J::Number(n) if n.is_i64() => SqlValue::from(n.as_i64().unwrap()),
96 J::Number(n) if n.is_u64() => SqlValue::from(n.as_u64().unwrap() as i64),
97 J::Number(n) => SqlValue::from(n.as_f64().unwrap()),
98 J::String(s) => SqlValue::from(s.clone()),
99 other => SqlValue::from(other.clone()),
100 }
101}