Skip to content

Commit c4abdae

Browse files
committed
refactor: preserve original types in Params instead of stringify-then-parse
Store serde_json::Value directly in Params enum instead of SQL strings, eliminating the lossy sql_string_to_json() reverse-parse roundtrip. This preserves type fidelity for server-side parameter binding (no more f64 coercion of large integers or bool case issues). - Add as_json_value() as primary method on Param trait - Change Params to store serde_json::Value instead of String - Add json_value_to_sql_string() for client-side binding path - Add Value::to_json_value() for ORM insert path - Simplify Python bindings to use py_to_json directly - Remove sql_string_to_json() reverse parser
1 parent b83f84a commit c4abdae

5 files changed

Lines changed: 210 additions & 207 deletions

File tree

bindings/python/src/utils.rs

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use std::collections::BTreeMap;
1616
use std::collections::HashMap;
1717

18-
use databend_driver::Param;
1918
use databend_driver::Params;
2019
use pyo3::exceptions::PyAttributeError;
2120
use pyo3::types::PyTuple;
@@ -46,84 +45,26 @@ pub(crate) fn to_sql_params(v: Option<Bound<PyAny>>) -> Params {
4645
let mut params = HashMap::new();
4746
for (k, v) in v.iter() {
4847
let k = k.extract::<String>().unwrap();
49-
let v = to_sql_string(v).unwrap();
48+
let v = py_to_json(v).unwrap();
5049
params.insert(k, v);
5150
}
5251
Params::NamedParams(params)
5352
} else if let Ok(v) = v.downcast::<PyList>() {
54-
let mut params = vec![];
55-
for v in v.iter() {
56-
let v = to_sql_string(v).unwrap();
57-
params.push(v);
58-
}
53+
let params: Vec<serde_json::Value> =
54+
v.iter().map(|v| py_to_json(v).unwrap()).collect();
5955
Params::QuestionParams(params)
6056
} else if let Ok(v) = v.downcast::<PyTuple>() {
61-
let mut params = vec![];
62-
for v in v.iter() {
63-
let v = to_sql_string(v).unwrap();
64-
params.push(v);
65-
}
57+
let params: Vec<serde_json::Value> =
58+
v.iter().map(|v| py_to_json(v).unwrap()).collect();
6659
Params::QuestionParams(params)
6760
} else {
68-
Params::QuestionParams(vec![to_sql_string(v).unwrap()])
61+
Params::QuestionParams(vec![py_to_json(v).unwrap()])
6962
}
7063
}
7164
None => Params::default(),
7265
}
7366
}
7467

75-
fn to_sql_string(v: Bound<PyAny>) -> PyResult<String> {
76-
if v.is_none() {
77-
return Ok("NULL".to_string());
78-
}
79-
match v.downcast::<PyAny>() {
80-
Ok(v) => {
81-
if let Ok(v) = v.extract::<String>() {
82-
Ok(v.as_sql_string())
83-
} else if let Ok(v) = v.extract::<bool>() {
84-
Ok(v.as_sql_string())
85-
} else if let Ok(v) = v.extract::<i64>() {
86-
Ok(v.as_sql_string())
87-
} else if let Ok(v) = v.extract::<f64>() {
88-
Ok(v.as_sql_string())
89-
} else {
90-
Err(PyAttributeError::new_err(format!(
91-
"Invalid parameter type for: {v:?}, expected str, bool, int or float"
92-
)))
93-
}
94-
}
95-
Err(e) => Err(e.into()),
96-
}
97-
}
98-
99-
/// Convert Python params directly to JSON values, preserving native types.
100-
pub(crate) fn to_json_params(v: Option<Bound<PyAny>>) -> Option<serde_json::Value> {
101-
match v {
102-
Some(v) => {
103-
if let Ok(v) = v.downcast::<PyDict>() {
104-
let mut map = serde_json::Map::new();
105-
for (k, v) in v.iter() {
106-
let k = k.extract::<String>().unwrap();
107-
let v = py_to_json(v).unwrap();
108-
map.insert(k, v);
109-
}
110-
Some(serde_json::Value::Object(map))
111-
} else if let Ok(v) = v.downcast::<PyList>() {
112-
let arr: Vec<serde_json::Value> =
113-
v.iter().map(|v| py_to_json(v).unwrap()).collect();
114-
Some(serde_json::Value::Array(arr))
115-
} else if let Ok(v) = v.downcast::<PyTuple>() {
116-
let arr: Vec<serde_json::Value> =
117-
v.iter().map(|v| py_to_json(v).unwrap()).collect();
118-
Some(serde_json::Value::Array(arr))
119-
} else {
120-
Some(serde_json::Value::Array(vec![py_to_json(v).unwrap()]))
121-
}
122-
}
123-
None => None,
124-
}
125-
}
126-
12768
fn py_to_json(v: Bound<PyAny>) -> PyResult<serde_json::Value> {
12869
if v.is_none() {
12970
return Ok(serde_json::Value::Null);

driver/src/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,9 @@ where
352352
let mut total_inserted = 0;
353353
for row in &self.rows {
354354
let values = row.to_values();
355-
let param_strings: Vec<String> =
356-
values.into_iter().map(|v| v.to_sql_string()).collect();
357-
let params = Params::QuestionParams(param_strings);
355+
let json_values: Vec<serde_json::Value> =
356+
values.into_iter().map(|v| v.to_json_value()).collect();
357+
let params = Params::QuestionParams(json_values);
358358
let inserted = connection.exec(&sql).bind(params).await?;
359359
total_inserted += inserted;
360360
}

0 commit comments

Comments
 (0)