use crate::error::{QuickDbError, QuickDbResult};
use crate::types::DataValue;
use std::collections::HashMap;
pub fn build_json_query_condition(
field_name: &str,
value: &DataValue,
placeholder: &str,
) -> QuickDbResult<(String, DataValue)> {
#[cfg(debug_assertions)]
{
rat_logger::debug!("PostgreSQL JSON查询策略分析:");
rat_logger::debug!(" 字段名: {}", field_name);
rat_logger::debug!(" 查询值: {:?}", value);
rat_logger::debug!(" 值类型: {:?}", std::mem::discriminant(value));
}
match value {
DataValue::String(s) => {
let trimmed = s.trim_start();
if (trimmed.starts_with('{') && trimmed.ends_with('}'))
|| (trimmed.starts_with('[') && trimmed.ends_with(']'))
{
match serde_json::from_str::<serde_json::Value>(s) {
Ok(json_val) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 精确JSON匹配,使用 @> 操作符");
Ok((
format!("{} @> {}", field_name, placeholder),
DataValue::Json(json_val),
))
}
Err(e) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" JSON格式无效: {},回退到文本搜索", e);
Ok((
format!("{}::text ILIKE {}", field_name, placeholder),
DataValue::String(format!("%{}%", s)),
))
}
}
} else {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 文本搜索,使用 ::text ILIKE");
Ok((
format!("{}::text ILIKE {}", field_name, placeholder),
DataValue::String(format!("%{}%", s)),
))
}
}
DataValue::Int(i) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 数值精确匹配,使用 @> 操作符");
let json_val = serde_json::Value::Number(serde_json::Number::from(*i));
Ok((
format!("{} @> ?", field_name),
DataValue::Json(json_val)
))
}
DataValue::UInt(u) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 无符号数值精确匹配,使用 @> 操作符");
let json_val = serde_json::Value::Number(serde_json::Number::from(*u));
Ok((
format!("{} @> ?", field_name),
DataValue::Json(json_val)
))
}
DataValue::Float(f) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 浮点数精确匹配,使用 @> 操作符");
let json_val = serde_json::Number::from_f64(*f)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null);
Ok((
format!("{} @> {}", field_name, placeholder),
DataValue::Json(json_val),
))
}
DataValue::Bool(b) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 布尔值精确匹配,使用 @> 操作符");
Ok((
format!("{} @> {}", field_name, placeholder),
DataValue::Json(serde_json::Value::Bool(*b)),
))
}
DataValue::Null => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: Null值检查");
Ok((format!("{} IS NULL", field_name), DataValue::Null))
}
DataValue::Json(json_val) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: JSON值精确匹配,使用 @> 操作符");
Ok((
format!("{} @> {}", field_name, placeholder),
DataValue::Json(json_val.clone()),
))
}
DataValue::Array(arr) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 数组精确匹配,转换为JSON");
let json_array: Vec<serde_json::Value> = arr
.iter()
.map(|item| match item {
DataValue::String(s) => serde_json::Value::String(s.clone()),
DataValue::Int(i) => serde_json::Value::Number(serde_json::Number::from(*i)),
DataValue::UInt(u) => serde_json::Value::Number(serde_json::Number::from(*u)),
DataValue::Float(f) => serde_json::Number::from_f64(*f)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
DataValue::Bool(b) => serde_json::Value::Bool(*b),
DataValue::Null => serde_json::Value::Null,
_ => serde_json::Value::String(item.to_string()),
})
.collect();
Ok((
format!("{} @> {}", field_name, placeholder),
DataValue::Json(serde_json::Value::Array(json_array)),
))
}
_ => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 策略: 其他类型,转换为文本搜索");
let text_value = value.to_string();
Ok((
format!("{}::text ILIKE {}", field_name, placeholder),
DataValue::String(format!("%{}%", text_value)),
))
}
}
}
pub fn convert_to_jsonb_value(value: &DataValue) -> QuickDbResult<DataValue> {
const MAX_JSONB_LENGTH: usize = 1024 * 1024;
match value {
DataValue::String(s) => {
if s.len() > MAX_JSONB_LENGTH {
return Err(QuickDbError::ValidationError {
field: "jsonb_value".to_string(),
message: format!("JSONB查询值过长,最大允许{}字节", MAX_JSONB_LENGTH),
});
}
let trimmed = s.trim_start();
if (trimmed.starts_with('{') && trimmed.ends_with('}'))
|| (trimmed.starts_with('[') && trimmed.ends_with(']'))
{
match serde_json::from_str::<serde_json::Value>(s) {
Ok(_) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" 检测到有效JSON字符串,使用精确匹配模式");
Ok(DataValue::String(s.clone()))
}
Err(_) => {
#[cfg(debug_assertions)]
rat_logger::debug!(" JSON字符串格式无效,使用文本搜索模式");
Ok(DataValue::String(format!("%{}%", s)))
}
}
} else {
#[cfg(debug_assertions)]
rat_logger::debug!(" 检测到普通字符串,使用文本搜索模式: '%{}%'", s);
Ok(DataValue::String(format!("%{}%", s)))
}
}
DataValue::Int(i) => Ok(DataValue::String(i.to_string())),
DataValue::UInt(u) => Ok(DataValue::String(u.to_string())),
DataValue::Float(f) => Ok(DataValue::String(f.to_string())),
DataValue::Bool(b) => Ok(DataValue::String(b.to_string())),
DataValue::Null => Ok(DataValue::String("null".to_string())),
DataValue::Array(arr) => {
if arr.len() > 1000 {
return Err(QuickDbError::ValidationError {
field: "jsonb_array".to_string(),
message: "JSONB查询数组元素过多,最大允许1000个元素".to_string(),
});
}
match serde_json::to_string(arr) {
Ok(json_str) => {
if json_str.len() > MAX_JSONB_LENGTH {
return Err(QuickDbError::ValidationError {
field: "jsonb_array".to_string(),
message: format!("JSONB查询数组过长,最大允许{}字节", MAX_JSONB_LENGTH),
});
}
Ok(DataValue::String(json_str))
}
Err(e) => Err(QuickDbError::SerializationError {
message: format!("数组序列化为JSON失败: {}", e),
}),
}
}
DataValue::Object(obj) => {
if obj.len() > 1000 {
return Err(QuickDbError::ValidationError {
field: "jsonb_object".to_string(),
message: "JSONB查询对象字段过多,最大允许1000个字段".to_string(),
});
}
match serde_json::to_string(obj) {
Ok(json_str) => {
if json_str.len() > MAX_JSONB_LENGTH {
return Err(QuickDbError::ValidationError {
field: "jsonb_object".to_string(),
message: format!("JSONB查询对象过长,最大允许{}字节", MAX_JSONB_LENGTH),
});
}
Ok(DataValue::String(json_str))
}
Err(e) => Err(QuickDbError::SerializationError {
message: format!("对象序列化为JSON失败: {}", e),
}),
}
}
DataValue::Json(json_val) => match serde_json::to_string(json_val) {
Ok(json_str) => {
if json_str.len() > MAX_JSONB_LENGTH {
return Err(QuickDbError::ValidationError {
field: "jsonb_value".to_string(),
message: format!("JSONB查询值过长,最大允许{}字节", MAX_JSONB_LENGTH),
});
}
Ok(DataValue::String(json_str))
}
Err(e) => Err(QuickDbError::SerializationError {
message: format!("JSON值序列化失败: {}", e),
}),
},
DataValue::DateTime(dt) => Ok(DataValue::String(dt.to_rfc3339())),
DataValue::DateTimeUTC(dt) => Ok(DataValue::String(dt.to_rfc3339())),
DataValue::Uuid(u) => Ok(DataValue::String(u.to_string())),
DataValue::Bytes(bytes) => {
if bytes.len() > 1024 {
return Err(QuickDbError::ValidationError {
field: "jsonb_bytes".to_string(),
message: "二进制数据过大,不能用于JSONB查询".to_string(),
});
}
Ok(DataValue::String(format!("\"{}\"", base64::encode(bytes))))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_json_query_condition_string_search() {
let (sql, param) =
build_json_query_condition("profile", &DataValue::String("Rust".to_string()), "$1")
.unwrap();
assert_eq!(sql, "profile::text ILIKE $1");
assert_eq!(param, DataValue::String("%Rust%".to_string()));
}
#[test]
fn test_json_query_condition_exact_match() {
let json_value = json!({"theme": "dark"});
let (sql, param) =
build_json_query_condition("settings", &DataValue::Json(json_value.clone()), "$1")
.unwrap();
assert_eq!(sql, "settings @> $1");
assert_eq!(param, DataValue::Json(json_value));
}
#[test]
fn test_json_query_condition_number() {
let (sql, param) = build_json_query_condition("age", &DataValue::Int(25), "$1").unwrap();
assert_eq!(sql, "age @> $1");
assert_eq!(param, DataValue::Json(json!(25)));
}
#[test]
fn test_convert_to_jsonb_value_string() {
let result = convert_to_jsonb_value(&DataValue::String("Rust".to_string())).unwrap();
assert_eq!(result, DataValue::String("%Rust%".to_string()));
}
#[test]
fn test_convert_to_jsonb_value_json_string() {
let json_str = "{\"theme\": \"dark\"}";
let result = convert_to_jsonb_value(&DataValue::String(json_str.to_string())).unwrap();
assert_eq!(result, DataValue::String(json_str.to_string()));
}
}