1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-04-15 11:56:36 +02:00

Доработка компоненты MySql

This commit is contained in:
Anton Titovets 2025-02-10 11:11:13 +03:00
parent 758bf2def0
commit 2bc14c9dc0

View File

@ -29,7 +29,7 @@ pub fn execute_query(
Err(e) => return format_json_error(&e.to_string()), Err(e) => return format_json_error(&e.to_string()),
}; };
let params_unboxed = params_ref.as_slice().iter().map(|boxed| boxed.as_ref()).collect::<Vec<_>>(); let params_unboxed: Vec<_> = params_ref.iter().map(AsRef::as_ref).collect();
if query.trim_start().to_uppercase().starts_with("SELECT") || force_result { if query.trim_start().to_uppercase().starts_with("SELECT") || force_result {
match client.query(&query, &params_unboxed) { match client.query(&query, &params_unboxed) {
@ -46,18 +46,47 @@ pub fn execute_query(
} }
} }
/// Конвертирует JSON-параметры в Postgres-совместимые типы
fn process_params(params: &Vec<Value>) -> Result<Vec<Box<dyn ToSql + Sync>>, String> {
let mut result = Vec::new();
for param in params {
let processed: Box<dyn ToSql + Sync> = match param {
Value::Null => Box::new(Option::<i32>::None),
Value::Bool(b) => Box::new(*b),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
Box::new(i)
} else if let Some(f) = n.as_f64() {
Box::new(f)
} else {
return Err("Invalid number".to_string());
}
}
Value::String(s) => Box::new(s.clone()),
Value::Object(obj) => process_object(obj)?,
_ => return Err("Unsupported parameter type".to_string()),
};
result.push(processed);
}
Ok(result)
}
fn process_object(object: &Map<String, Value>) -> Result<Box<dyn ToSql + Sync>, String> { fn process_object(object: &Map<String, Value>) -> Result<Box<dyn ToSql + Sync>, String> {
if object.len() != 1 { if object.len() != 1 {
return Err("Object must have exactly one key-value pair specifying the type and value".to_string()); return Err("Object must have exactly one key-value pair specifying the type and value".to_string());
} }
let (key, value) = object.iter().next().unwrap(); let (key, value) = object.iter().next()
match key.as_str() { .ok_or_else(|| "Empty object: expected one key-value pair".to_string())?;
let key_upper = key.as_str().to_uppercase();
match key_upper.as_str() {
"BOOL" => value "BOOL" => value
.as_bool() .as_bool()
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>) .map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
.ok_or_else(|| "Invalid value for BOOL".to_string()), .ok_or_else(|| "Invalid value for BOOL".to_string()),
"\"char\"" => value "\"CHAR\"" => value
.as_i64() .as_i64()
.and_then(|v| i8::try_from(v).ok()) .and_then(|v| i8::try_from(v).ok())
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>) .map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
@ -120,7 +149,7 @@ fn process_object(object: &Map<String, Value>) -> Result<Box<dyn ToSql + Sync>,
"TIMESTAMP" | "TIMESTAMP WITH TIME ZONE" => value "TIMESTAMP" | "TIMESTAMP WITH TIME ZONE" => value
.as_i64() .as_i64()
.map(|v| { .map(|v| {
let duration = UNIX_EPOCH + std::time::Duration::from_secs(v as u64); let duration = UNIX_EPOCH + std::time::Duration::from_millis(v as u64 * 1000);
let system_time = SystemTime::from(duration); let system_time = SystemTime::from(duration);
Box::new(system_time) as Box<dyn ToSql + Sync> Box::new(system_time) as Box<dyn ToSql + Sync>
}) })
@ -134,31 +163,6 @@ fn process_object(object: &Map<String, Value>) -> Result<Box<dyn ToSql + Sync>,
} }
} }
/// Конвертирует JSON-параметры в Postgres-совместимые типы
fn process_params(params: &Vec<Value>) -> Result<Vec<Box<dyn ToSql + Sync>>, String> {
let mut result = Vec::new();
for param in params {
let processed: Box<dyn ToSql + Sync> = match param {
Value::Null => Box::new(Option::<i32>::None),
Value::Bool(b) => Box::new(*b),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
Box::new(i)
} else if let Some(f) = n.as_f64() {
Box::new(f)
} else {
return Err("Invalid number".to_string());
}
}
Value::String(s) => Box::new(s.clone()),
Value::Object(obj) => process_object(obj)?,
_ => return Err("Unsupported parameter type".to_string()),
};
result.push(processed);
}
Ok(result)
}
fn rows_to_json(rows: Vec<postgres::Row>) -> String { fn rows_to_json(rows: Vec<postgres::Row>) -> String {
let mut result = Vec::new(); let mut result = Vec::new();
@ -166,75 +170,62 @@ fn rows_to_json(rows: Vec<postgres::Row>) -> String {
let mut row_map = Map::new(); let mut row_map = Map::new();
for column in row.columns() { for column in row.columns() {
let column_name = column.name(); // Получаем &str вместо String let column_name = column.name();
let column_type = column.type_().name(); let column_type = column.type_().name();
let value = match column_type { let value = match column_type.to_lowercase().as_str() {
"bool" | "BOOL" => { "bool" => row.get::<_, Option<bool>>(column_name).map(Value::Bool).unwrap_or(Value::Null),
let val: bool = row.get(column_name); "int2" | "smallint" | "smallserial" => row.get::<_, Option<i16>>(column_name)
Value::Bool(val) .map(|v| Value::Number(v.into()))
} .unwrap_or(Value::Null),
"\"char\"" => { "int4" | "int" | "serial" => row.get::<_, Option<i32>>(column_name)
let val: i8 = row.get(column_name); .map(|v| Value::Number(v.into()))
Value::Number(val.into()) .unwrap_or(Value::Null),
} "oid" => row.get::<_, Option<u32>>(column_name)
"int2" | "SMALLINT" | "SMALLSERIAL" => { .map(|v| Value::Number(v.into()))
let val: i16 = row.get(column_name); .unwrap_or(Value::Null),
Value::Number(val.into()) "int8" | "bigint" | "bigserial" => row.get::<_, Option<i64>>(column_name)
} .map(|v| Value::Number(v.into()))
"int4" | "INT" | "SERIAL" => { .unwrap_or(Value::Null),
let val: i32 = row.get(column_name); "float4" | "real" => row.get::<_, Option<f32>>(column_name)
Value::Number(val.into()) .map(|v| serde_json::Number::from_f64(v as f64).map(Value::Number).unwrap_or(Value::Null))
} .unwrap_or(Value::Null),
"oid" | "OID" => { "float8" | "double precision" => row.get::<_, Option<f64>>(column_name)
let val: u32 = row.get(column_name); .map(|v| serde_json::Number::from_f64(v).map(Value::Number).unwrap_or(Value::Null))
Value::Number(val.into()) .unwrap_or(Value::Null),
} "varchar" | "text" | "char" | "citext" | "name" | "unknown" => row.get::<_, Option<String>>(column_name)
"int8" | "BIGINT" | "BIGSERIAL" => { .map(Value::String)
let val: i64 = row.get(column_name); .unwrap_or(Value::Null),
Value::Number(val.into()) "bytea" => row.get::<_, Option<Vec<u8>>>(column_name)
} .map(|v| Value::String(general_purpose::STANDARD.encode(v)))
"float4" | "REAL" => { .unwrap_or(Value::Null),
let val: f32 = row.get(column_name); "hstore" => row.get::<_, Option<HashMap<String, Option<String>>>>(column_name)
Value::Number(serde_json::Number::from_f64(val as f64).unwrap_or_else(|| serde_json::Number::from(0))) .map(|hstore| {
} let mut map = Map::new();
"float8" | "DOUBLE PRECISION" => { for (k, v) in hstore {
let val: f64 = row.get(column_name); map.insert(k, v.map(Value::String).unwrap_or(Value::Null));
Value::Number(serde_json::Number::from_f64(val).unwrap_or_else(|| serde_json::Number::from(0))) }
} Value::Object(map)
"varchar" | "text" | "char" | "citext" | "name" | "unknown" | "VARCHAR" | "CHAR(n)" | "TEXT" | "CITEXT" | "NAME" | "UNKNOWN" => { })
let val: String = row.get(column_name); .unwrap_or(Value::Null),
Value::String(val) "timestamp" | "timestamptz" => row.get::<_, Option<SystemTime>>(column_name)
} .map(|time| {
"ltree" | "lquery" | "ltxtquery" | "LTREE" | "LQUERY" | "LTXTQUERY" => { match time.duration_since(SystemTime::UNIX_EPOCH) {
let val: String = row.get(column_name); Ok(d) => Value::Number(d.as_secs().into()),
Value::String(val) Err(_) => match SystemTime::UNIX_EPOCH.duration_since(time) {
} Ok(d) => Value::Number(-(d.as_secs() as i64).into()), // Отрицательное значение для даты до UNIX_EPOCH
"bytea" | "BYTEA" => { Err(_) => Value::Null, // Это вообще не должно произойти
let val: Vec<u8> = row.get(column_name); },
Value::String(general_purpose::STANDARD.encode(val)) }
} })
"hstore" | "HSTORE" => { .unwrap_or(Value::Null),
let val: HashMap<String, Option<String>> = row.get(column_name); "inet" => row.get::<_, Option<IpAddr>>(column_name)
let mut map = Map::new(); .map(|ip| Value::String(ip.to_string()))
for (k, v) in val { .unwrap_or(Value::Null),
map.insert(k, v.map(Value::String).unwrap_or(Value::Null)); _ => Value::Null,
}
Value::Object(map)
}
"timestamp" | "timestamptz" | "TIMESTAMP" | "TIMESTAMP WITH TIME ZONE" => {
let val: SystemTime = row.get(column_name);
let duration = val.duration_since(SystemTime::UNIX_EPOCH).unwrap();
Value::Number(duration.as_secs().into())
}
"inet" | "INET" => {
let val: IpAddr = row.get(column_name);
Value::String(val.to_string())
}
_ => Value::Null, // Неизвестный тип
}; };
row_map.insert(column_name.to_string(), value); // Вставляем в Map с ключом String row_map.insert(column_name.to_string(), value);
} }
result.push(Value::Object(row_map)); result.push(Value::Object(row_map));