use rat_logger::{LevelFilter, LoggerBuilder, handler::term::TermConfig};
use rat_quickdb::manager::health_check;
use rat_quickdb::model::FieldType;
use rat_quickdb::types::{
ConnectionConfig, DatabaseType, LogicalOperator, PoolConfig, QueryConditionGroup, QueryOptions,
SortConfig, SortDirection,
};
use rat_quickdb::*;
use rat_quickdb::{
DataValue, ModelManager, ModelOperations, QueryCondition, QueryOperator, array_field,
field_types,
};
fn display_array_test_result(index: usize, result: &ArrayTestModel) {
let tags_json = serde_json::to_string(&result.tags).unwrap_or_else(|_| "[]".to_string());
let category_ids_json =
serde_json::to_string(&result.category_ids).unwrap_or_else(|_| "[]".to_string());
let ratings_json = serde_json::to_string(&result.ratings).unwrap_or_else(|_| "[]".to_string());
println!(" {}. {}", index + 1, result.name);
println!(" tags: {}", tags_json);
println!(" category_ids: {}", category_ids_json);
println!(" ratings: {}", ratings_json);
println!();
}
define_model! {
struct ArrayTestModel {
id: String,
name: String,
tags: Vec<String>, category_ids: Vec<i64>, ratings: Vec<f64>, }
collection = "array_test",
database = "main",
fields = {
id: string_field(None, None, None).required().unique(),
name: string_field(None, None, None).required(),
tags: array_field(field_types!(string), Some(10), Some(0)),
category_ids: array_field(field_types!(integer), Some(20), Some(0)),
ratings: array_field(field_types!(float), Some(15), Some(0)),
}
}
#[tokio::main]
async fn main() -> QuickDbResult<()> {
LoggerBuilder::new()
.add_terminal_with_config(TermConfig::default())
.init()
.expect("日志初始化失败");
println!("🚀 测试 SQLite Array 字段 IN 查询功能");
println!("===============================\n");
cleanup_test_files().await;
println!("1. 配置SQLite数据库...");
let db_config = DatabaseConfig {
alias: "main".to_string(),
db_type: DatabaseType::SQLite,
connection: ConnectionConfig::SQLite {
path: "./array_test.db".to_string(),
create_if_missing: true,
},
pool: PoolConfig::builder()
.max_connections(10)
.min_connections(1)
.connection_timeout(10)
.idle_timeout(300)
.max_lifetime(1800)
.max_retries(3)
.retry_interval_ms(1000)
.keepalive_interval_sec(60)
.health_check_timeout_sec(10)
.build()
.unwrap(),
id_strategy: IdStrategy::ObjectId,
cache: None,
};
add_database(db_config).await?;
println!("✓ SQLite数据库配置完成");
println!("\n2. 创建测试数据...");
let test_data = vec![
ArrayTestModel {
id: generate_object_id(),
name: "iPhone 15".to_string(),
tags: vec![
"apple".to_string(),
"smartphone".to_string(),
"premium".to_string(),
],
category_ids: vec![1, 5, 10],
ratings: vec![4.5, 4.8, 4.2],
},
ArrayTestModel {
id: generate_object_id(),
name: "Samsung Galaxy S24".to_string(),
tags: vec![
"samsung".to_string(),
"smartphone".to_string(),
"android".to_string(),
],
category_ids: vec![1, 5, 11],
ratings: vec![4.3, 4.6, 4.1],
},
ArrayTestModel {
id: generate_object_id(),
name: "MacBook Pro".to_string(),
tags: vec![
"apple".to_string(),
"laptop".to_string(),
"premium".to_string(),
],
category_ids: vec![2, 5, 12],
ratings: vec![4.7, 4.9, 4.8],
},
ArrayTestModel {
id: generate_object_id(),
name: "Dell XPS 13".to_string(),
tags: vec![
"dell".to_string(),
"laptop".to_string(),
"business".to_string(),
],
category_ids: vec![2, 5, 13],
ratings: vec![4.2, 4.4, 4.3],
},
];
for (i, item) in test_data.iter().enumerate() {
match item.save().await {
Ok(_) => println!("✓ 创建测试数据 {}: {}", i + 1, item.name),
Err(e) => {
eprintln!("❌ 创建测试数据失败 {}: {}", i + 1, e);
return Err(e);
}
}
}
println!("\n3. Array 字段 IN 查询测试...");
println!("\n3.1 查找标签包含 'apple' 的产品:");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::String("apple".to_string())]),
}],
None,
)
.await
{
Ok(results) => {
println!("✓ 找到 {} 个产品:", results.len());
for (i, result) in results.iter().enumerate() {
display_array_test_result(i, result);
}
}
Err(e) => {
eprintln!("❌ 查询失败: {}", e);
}
}
println!("\n3.2 查找标签包含 'laptop' 或 'smartphone' 的产品:");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![
DataValue::String("laptop".to_string()),
DataValue::String("smartphone".to_string()),
]),
}],
None,
)
.await
{
Ok(results) => {
println!("✓ 找到 {} 个产品:", results.len());
for (i, result) in results.iter().enumerate() {
display_array_test_result(i, result);
}
}
Err(e) => {
eprintln!("❌ 查询失败: {}", e);
}
}
println!("\n3.3 查找分类ID包含 1 的产品:");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "category_ids".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::Int(1)]),
}],
None,
)
.await
{
Ok(results) => {
println!("✓ 找到 {} 个产品:", results.len());
for (i, result) in results.iter().enumerate() {
display_array_test_result(i, result);
}
}
Err(e) => {
eprintln!("❌ 查询失败: {}", e);
}
}
println!("\n3.4 查找评分包含 4.8 的产品:");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "ratings".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::Float(4.8)]),
}],
None,
)
.await
{
Ok(results) => {
println!("✓ 找到 {} 个产品:", results.len());
for (i, result) in results.iter().enumerate() {
display_array_test_result(i, result);
}
}
Err(e) => {
eprintln!("❌ 查询失败: {}", e);
}
}
println!("\n3.5 测试 Array 字段的 NOT IN 查询(应该报错):");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::NotIn,
value: DataValue::Array(vec![DataValue::String("apple".to_string())]),
}],
None,
)
.await
{
Ok(_) => {
eprintln!("❌ 意外成功,应该报错");
}
Err(e) => {
println!("✓ 正确报错: {}", e);
}
}
println!("\n4.6 测试不支持类型的 IN 查询(应该报错):");
match ModelManager::<ArrayTestModel>::find(
vec![QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::Bool(true)]),
}],
None,
)
.await
{
Ok(_) => {
eprintln!("❌ 意外成功,应该报错");
}
Err(e) => {
println!("✓ 正确报错: {}", e);
}
}
println!("\n4. 复杂 Array 查询测试...");
println!("\n4.1 复杂组合查询: (tags包含'apple'或'samsung') AND (category_ids包含1)");
let complex_condition = QueryConditionGroup::Group {
operator: LogicalOperator::And,
conditions: vec![
QueryConditionGroup::Group {
operator: LogicalOperator::Or,
conditions: vec![
QueryConditionGroup::Single(QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::String("apple".to_string())]),
}),
QueryConditionGroup::Single(QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::String("samsung".to_string())]),
}),
],
},
QueryConditionGroup::Single(QueryCondition {
field: "category_ids".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![DataValue::Int(1)]),
}),
],
};
match ModelManager::<ArrayTestModel>::find_with_groups(vec![complex_condition], None).await {
Ok(results) => {
println!("✓ 找到 {} 个产品:", results.len());
for (i, result) in results.iter().enumerate() {
display_array_test_result(i, result);
}
}
Err(e) => {
eprintln!("❌ 复杂查询失败: {}", e);
}
}
println!("\n✅ Array 字段复杂查询测试完成!");
println!("📁 数据库文件保留: array_test.db(可用于验证数据正确性)");
Ok(())
}
async fn cleanup_test_files() {
let test_files = vec![
"./array_test.db",
"./array_test.db-wal",
"./array_test.db-shm",
];
for file in test_files {
if let Err(e) = tokio::fs::remove_file(file).await {
if !e.to_string().contains("No such file or directory") {
rat_logger::warn!("清理文件失败 {}: {}", file, e);
}
}
}
}