mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2025-04-15 11:56:36 +02:00
Доработка компоненты MySql
This commit is contained in:
parent
758bf2def0
commit
2bc14c9dc0
@ -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, ¶ms_unboxed) {
|
match client.query(&query, ¶ms_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));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user