use chrono::Utc;
use rat_logger::{LevelFilter, LoggerBuilder, debug, handler::term::TermConfig};
use rat_quickdb::types::UpdateOperation;
use rat_quickdb::types::*;
use rat_quickdb::types::{LogicalOperator, QueryConditionGroup, QueryConditionWithConfig};
use rat_quickdb::*;
use rat_quickdb::{
ModelManager, ModelOperations, boolean_field, datetime_field, float_field, integer_field,
string_field, uuid_field,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{Instant, SystemTime};
define_model! {
struct User {
id: String,
username: String,
email: String,
full_name: String,
age: Option<i32>,
department: String,
is_active: bool,
salary: Option<f64>,
created_at: chrono::DateTime<chrono::Utc>,
updated_at: Option<chrono::DateTime<chrono::Utc>>,
}
collection = "query_demo_users",
database = "main",
fields = {
id: uuid_field().required().unique(),
username: string_field(None, None, None).required().unique(),
email: string_field(None, None, None).required().unique(),
full_name: string_field(None, None, None).required(),
age: integer_field(None, None),
department: string_field(None, None, None).required(),
is_active: boolean_field().required(),
salary: float_field(None, None),
created_at: datetime_field().required(),
updated_at: datetime_field(),
}
indexes = [
{ fields: ["username"], unique: true, name: "idx_username" },
{ fields: ["email"], unique: true, name: "idx_email" },
{ fields: ["department"], unique: false, name: "idx_department" },
{ fields: ["is_active"], unique: false, name: "idx_active" },
{ fields: ["age"], unique: false, name: "idx_age" },
{ fields: ["salary"], unique: false, name: "idx_salary" },
],
}
define_model! {
struct Product {
id: String,
name: String,
category: String,
price: f64,
stock: i32,
is_available: bool,
rating: Option<f64>,
tags: Vec<String>,
created_at: chrono::DateTime<chrono::Utc>,
updated_at: Option<chrono::DateTime<chrono::Utc>>,
}
collection = "query_demo_products",
database = "main",
fields = {
id: uuid_field().required().unique(),
name: string_field(None, None, None).required(),
category: string_field(None, None, None).required(),
price: float_field(None, None).required(),
stock: integer_field(None, None).required(),
is_available: boolean_field().required(),
rating: float_field(None, None),
tags: array_field(field_types!(string), Some(50), Some(0)),
created_at: datetime_field().required(),
updated_at: datetime_field(),
}
indexes = [
{ fields: ["name"], unique: false, name: "idx_name" },
{ fields: ["category"], unique: false, name: "idx_category" },
{ fields: ["price"], unique: false, name: "idx_price" },
{ fields: ["stock"], unique: false, name: "idx_stock" },
{ fields: ["is_available"], unique: false, name: "idx_available" },
{ fields: ["rating"], unique: false, name: "idx_rating" },
],
}
#[derive(Debug)]
struct QueryStats {
batch_operations: u64,
complex_queries: u64,
total_time_ms: u64,
successful_operations: u64,
}
impl QueryStats {
fn new() -> Self {
Self {
batch_operations: 0,
complex_queries: 0,
total_time_ms: 0,
successful_operations: 0,
}
}
fn add_operation(&mut self, duration_ms: u64, success: bool, is_batch: bool) {
self.total_time_ms += duration_ms;
self.successful_operations += if success { 1 } else { 0 };
if is_batch {
self.batch_operations += 1;
} else {
self.complex_queries += 1;
}
}
fn get_summary(&self) -> String {
format!(
"查询操作统计:\n\
├─ 批量操作: {} 次\n\
├─ 复杂查询: {} 次\n\
├─ 总操作数: {} 次\n\
├─ 成功率: {:.1}%\n\
└─ 平均耗时: {:.1}ms/次",
self.batch_operations,
self.complex_queries,
self.batch_operations + self.complex_queries,
if self.batch_operations + self.complex_queries > 0 {
self.successful_operations as f64
/ (self.batch_operations + self.complex_queries) as f64
* 100.0
} else {
0.0
},
if self.batch_operations + self.complex_queries > 0 {
self.total_time_ms as f64 / (self.batch_operations + self.complex_queries) as f64
} else {
0.0
}
)
}
}
async fn cleanup_test_data() {
println!("清理测试数据...");
if let Err(e) = rat_quickdb::drop_table("main", "query_demo_users").await {
debug!("清理用户表失败: {}", e);
}
if let Err(e) = rat_quickdb::drop_table("main", "query_demo_products").await {
debug!("清理产品表失败: {}", e);
}
}
async fn create_test_data(count: usize) -> Result<Vec<String>, Box<dyn std::error::Error>> {
println!("创建 {} 条测试用户数据...", count);
let mut user_ids = Vec::new();
for i in 0..count {
let user = User {
id: String::new(),
username: format!("user_{}", i),
email: format!("user{}@example.com", i),
full_name: format!("测试用户 {}", i),
age: Some((20 + (i % 50)) as i32),
department: match i % 4 {
0 => "技术部".to_string(),
1 => "销售部".to_string(),
2 => "人事部".to_string(),
_ => "财务部".to_string(),
},
is_active: i % 5 != 0,
salary: Some(30000.0 + (i as f64 * 1000.0)),
created_at: Utc::now(),
updated_at: None,
};
let user_id = user.save().await?;
user_ids.push(user_id);
}
Ok(user_ids)
}
async fn create_product_test_data(count: usize) -> Result<(), Box<dyn std::error::Error>> {
println!("创建 {} 条测试产品数据...", count);
for i in 0..count {
let (name, category) = if i < 5 {
let cat = match i % 3 {
0 => "Electronics",
1 => "Office",
_ => "Lifestyle",
};
(format!("PRODUCT {}", i), cat.to_string())
} else {
(
format!("产品 {}", i),
match i % 3 {
0 => "电子产品".to_string(),
1 => "办公用品".to_string(),
_ => "生活用品".to_string(),
},
)
};
let product = Product {
id: String::new(),
name,
category,
price: (100 + i) as f64 * 1.5,
stock: (10 + i * 2) as i32,
is_available: i % 3 != 0,
rating: Some((3.0 + (i % 10) as f64 * 0.5).min(5.0)),
tags: vec![
match i % 5 {
0 => "热销".to_string(),
1 => "新品".to_string(),
2 => "推荐".to_string(),
3 => "特价".to_string(),
_ => "限量".to_string(),
},
format!("类别{}", i % 3),
],
created_at: Utc::now(),
updated_at: None,
};
product.save().await?;
}
Ok(())
}
async fn demonstrate_batch_operations() -> Result<QueryStats, Box<dyn std::error::Error>> {
println!("\n=== 批量操作演示 ===");
let mut stats = QueryStats::new();
let user_ids = create_test_data(100).await?;
println!("\n执行批量更新...");
let start = Instant::now();
let mut update_data = HashMap::new();
update_data.insert(
"department".to_string(),
DataValue::String("升级部门".to_string()),
);
update_data.insert("salary".to_string(), DataValue::Float(50000.0));
let update_conditions = vec![QueryCondition {
field: "age".to_string(),
operator: QueryOperator::Gte,
value: DataValue::Int(40),
}];
let operations = vec![
UpdateOperation::set("department", DataValue::String("升级部门".to_string())),
UpdateOperation::set("salary", DataValue::Float(50000.0)),
UpdateOperation::set("updated_at", DataValue::from(Utc::now())),
];
let update_result = User::update_many_with_operations(update_conditions, operations).await;
let update_time = start.elapsed().as_millis() as u64;
match update_result {
Ok(updated_count) => {
println!(
"✅ 批量更新成功: {} 条记录,耗时 {}ms",
updated_count, update_time
);
stats.add_operation(update_time, true, true);
}
Err(e) => {
println!("❌ 批量更新失败: {},耗时 {}ms", e, update_time);
stats.add_operation(update_time, false, true);
}
}
println!("\n执行批量删除...");
let start = Instant::now();
let delete_conditions = vec![QueryCondition {
field: "is_active".to_string(),
operator: QueryOperator::Eq,
value: DataValue::Bool(false),
}];
let delete_result = User::delete_many(delete_conditions).await;
let delete_time = start.elapsed().as_millis() as u64;
match delete_result {
Ok(deleted_count) => {
println!(
"✅ 批量删除成功: {} 条记录,耗时 {}ms",
deleted_count, delete_time
);
stats.add_operation(delete_time, true, true);
}
Err(e) => {
println!("❌ 批量删除失败: {},耗时 {}ms", e, delete_time);
stats.add_operation(delete_time, false, true);
}
}
Ok(stats)
}
async fn demonstrate_complex_queries() -> Result<QueryStats, Box<dyn std::error::Error>> {
println!("\n=== 复杂查询演示 ===");
let mut stats = QueryStats::new();
create_product_test_data(50).await?;
println!("\n1. 简单条件查询...");
let start = Instant::now();
let simple_conditions = vec![QueryCondition {
field: "category".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String("电子产品".to_string()),
}];
let simple_result = ModelManager::<Product>::find(simple_conditions, None).await?;
let simple_time = start.elapsed().as_millis() as u64;
println!(
"✅ 电子产品查询: {} 条记录,耗时 {}ms",
simple_result.len(),
simple_time
);
stats.add_operation(simple_time, true, false);
println!("\n2. 复杂AND/OR混用查询...");
let start = Instant::now();
let complex_condition = QueryConditionGroup::Group {
operator: LogicalOperator::And,
conditions: vec![
QueryConditionGroup::Single(QueryCondition {
field: "is_available".to_string(),
operator: QueryOperator::Eq,
value: DataValue::Bool(true),
}),
QueryConditionGroup::Group {
operator: LogicalOperator::Or,
conditions: vec![
QueryConditionGroup::Single(QueryCondition {
field: "category".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String("电子产品".to_string()),
}),
QueryConditionGroup::Single(QueryCondition {
field: "price".to_string(),
operator: QueryOperator::Gte,
value: DataValue::Float(180.0),
}),
],
},
],
};
let complex_result =
ModelManager::<Product>::find_with_groups(vec![complex_condition.clone()], None).await?;
let complex_time = start.elapsed().as_millis() as u64;
println!(
"✅ AND/OR混用查询: {} 条记录,耗时 {}ms",
complex_result.len(),
complex_time
);
stats.add_operation(complex_time, true, false);
println!("\n2.5. 使用 count_with_groups 统计...");
let start = Instant::now();
let count_result =
ModelManager::<Product>::count_with_groups(vec![complex_condition]).await?;
let count_time = start.elapsed().as_millis() as u64;
println!(
"✅ count_with_groups: {} 条记录,耗时 {}ms",
count_result, count_time
);
println!(
" 验证: find_with_groups 返回 {} 条,count_with_groups 返回 {} 条",
complex_result.len(),
count_result
);
stats.add_operation(count_time, true, false);
println!("\n3. 排序查询...");
let start = Instant::now();
let sort_options = QueryOptions {
sort: vec![
SortConfig {
field: "price".to_string(),
direction: SortDirection::Desc,
},
SortConfig {
field: "name".to_string(),
direction: SortDirection::Asc,
},
],
..Default::default()
};
let sort_result = ModelManager::<Product>::find(vec![], Some(sort_options)).await?;
let sort_time = start.elapsed().as_millis() as u64;
println!(
"✅ 排序查询: {} 条记录,耗时 {}ms",
sort_result.len(),
sort_time
);
println!(" 最贵3个产品:");
for (i, product) in sort_result.iter().take(3).enumerate() {
println!(
" {}. {} - ${:.2} - {}",
i + 1,
product.name,
product.price,
product.category
);
}
stats.add_operation(sort_time, true, false);
println!("\n4. 分页查询...");
let start = Instant::now();
let pagination_options = QueryOptions {
pagination: Some(PaginationConfig { skip: 10, limit: 5 }),
sort: vec![SortConfig {
field: "rating".to_string(),
direction: SortDirection::Desc,
}],
..Default::default()
};
let page_result = ModelManager::<Product>::find(vec![], Some(pagination_options)).await?;
let page_time = start.elapsed().as_millis() as u64;
println!(
"✅ 分页查询: {} 条记录,耗时 {}ms",
page_result.len(),
page_time
);
println!(" 第2页产品 (按评分排序):");
for (i, product) in page_result.iter().enumerate() {
println!(
" {}. {} - 评分: {:.1} - ${:.2}",
i + 11,
product.name,
product.rating.unwrap_or(0.0),
product.price
);
}
stats.add_operation(page_time, true, false);
println!("\n5. 字段选择查询...");
let start = Instant::now();
let field_options = QueryOptions {
fields: vec![
"name".to_string(),
"price".to_string(),
"category".to_string(),
],
..Default::default()
};
let field_result = ModelManager::<Product>::find(vec![], Some(field_options)).await?;
let field_time = start.elapsed().as_millis() as u64;
println!(
"✅ 字段选择查询: {} 条记录,耗时 {}ms",
field_result.len(),
field_time
);
println!(" 前5个产品 (仅显示名称、价格、类别):");
for (i, product) in field_result.iter().take(5).enumerate() {
println!(
" {}. {} - ${:.2} - {}",
i + 1,
product.name,
product.price,
product.category
);
}
stats.add_operation(field_time, true, false);
println!("\n6. IN查询 (数组字段)...");
let start = Instant::now();
let in_conditions = vec![QueryCondition {
field: "tags".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![
DataValue::String("热销".to_string()),
DataValue::String("新品".to_string()),
DataValue::String("推荐".to_string()),
DataValue::String("特价".to_string()),
DataValue::String("限量".to_string()),
]),
}];
let in_result = ModelManager::<Product>::find(in_conditions, None).await?;
let in_time = start.elapsed().as_millis() as u64;
println!("✅ IN查询: {} 条记录,耗时 {}ms", in_result.len(), in_time);
println!(" 包含'热销'或'新品'标签的产品:");
for (i, product) in in_result.iter().take(3).enumerate() {
println!(" {}. {} - 标签: {:?}", i + 1, product.name, product.tags);
}
stats.add_operation(in_time, true, false);
println!("\n6.1 IN查询 (普通字段)...");
let start = Instant::now();
let in_string_conditions = vec![QueryCondition {
field: "category".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![
DataValue::String("电子产品".to_string()),
DataValue::String("家居用品".to_string()),
DataValue::String("图书".to_string()),
]),
}];
let in_string_result = ModelManager::<Product>::find(in_string_conditions, None).await?;
let in_string_time = start.elapsed().as_millis() as u64;
println!(
"✅ IN查询(普通string字段): {} 条记录,耗时 {}ms",
in_string_result.len(),
in_string_time
);
println!(" 包含'电子产品'、'家居用品'或'图书'分类的产品:");
for (i, product) in in_string_result.iter().take(3).enumerate() {
println!(" {}. {} - 分类: {:?}", i + 1, product.name, product.category);
}
stats.add_operation(in_string_time, true, false);
println!("\n6.2 IN查询 (普通整数字段)...");
let start = Instant::now();
let in_int_conditions = vec![QueryCondition {
field: "stock".to_string(),
operator: QueryOperator::In,
value: DataValue::Array(vec![
DataValue::Int(10),
DataValue::Int(20),
DataValue::Int(30),
]),
}];
let in_int_result = ModelManager::<Product>::find(in_int_conditions, None).await?;
let in_int_time = start.elapsed().as_millis() as u64;
println!(
"✅ IN查询(普通int字段): {} 条记录,耗时 {}ms",
in_int_result.len(),
in_int_time
);
println!(" 库存为10、20、30的产品:");
for (i, product) in in_int_result.iter().take(3).enumerate() {
println!(" {}. {} - 库存: {:?}", i + 1, product.name, product.stock);
}
stats.add_operation(in_int_time, true, false);
println!("\n7. 大小写不敏感查询测试...");
let start = Instant::now();
let case_sensitive_conditions = vec![QueryCondition {
field: "category".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String("ELECTRONICS".to_string()),
}];
let case_sensitive_result =
ModelManager::<Product>::find(case_sensitive_conditions, None).await?;
println!(
" 大小写敏感查询 'ELECTRONICS': {} 条记录",
case_sensitive_result.len()
);
let case_insensitive_conditions = vec![QueryConditionWithConfig {
field: "category".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String("electronics".to_string()),
case_insensitive: true,
}];
let case_insensitive_result =
ModelManager::<Product>::find_with_config(case_insensitive_conditions, None).await?;
let ci_time = start.elapsed().as_millis() as u64;
println!(
" 大小写不敏感查询 'electronics': {} 条记录,耗时 {}ms",
case_insensitive_result.len(),
ci_time
);
if case_insensitive_result.len() > 0 {
println!(" ✅ 大小写不敏感查询成功");
println!(" 找到的产品: {}", case_insensitive_result[0].name);
} else {
println!(" ⚠️ 大小写不敏感查询未找到结果");
}
stats.add_operation(ci_time, true, false);
println!("\n8. UUID字段查询(重要场景)...");
println!(" 📝 说明: 在 MySQL/SQLite/MongoDB 中,uuid_field() 存储为字符串");
println!(" 📝 查询时传入 DataValue::String 即可正常查询,框架会自动处理类型转换");
let test_user = User {
id: String::new(),
username: "uuid_test_user".to_string(),
email: "uuid_test@example.com".to_string(),
full_name: "UUID测试用户".to_string(),
age: Some(25),
department: "技术部".to_string(),
is_active: true,
salary: Some(10000.0),
created_at: Utc::now(),
updated_at: None,
};
let test_user_id = test_user.save().await?;
println!(" 创建测试用户 ID: {}", test_user_id);
let start = Instant::now();
let uuid_query_conditions = vec![QueryCondition {
field: "id".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String(test_user_id.clone()),
}];
let uuid_result = ModelManager::<User>::find(uuid_query_conditions, None).await?;
let uuid_query_time = start.elapsed().as_millis() as u64;
if !uuid_result.is_empty() {
println!(" ✅ UUID字段查询成功: 找到用户 '{}', 耗时 {}ms",
uuid_result[0].username, uuid_query_time);
} else {
println!(" ❌ UUID字段查询失败: 未找到用户");
}
println!(" 测试外键 UUID 查询场景...");
let username_query = vec![QueryCondition {
field: "username".to_string(),
operator: QueryOperator::Eq,
value: DataValue::String("uuid_test_user".to_string()),
}];
let username_result = ModelManager::<User>::find(username_query, None).await?;
if !username_result.is_empty() {
println!(" ✅ 普通字符串字段查询成功: 找到用户 '{}'", username_result[0].full_name);
}
stats.add_operation(uuid_query_time, true, false);
Ok(stats)
}
async fn performance_benchmark() -> Result<(), Box<dyn std::error::Error>> {
println!("\n=== 性能基准测试 ===");
println!("创建性能测试数据...");
let start = Instant::now();
create_performance_test_data(500).await?;
let create_time = start.elapsed();
let test_queries = vec![
(
"单字段查询",
vec![QueryCondition {
field: "is_available".to_string(),
operator: QueryOperator::Eq,
value: DataValue::Bool(true),
}],
),
(
"双字段AND查询",
vec![
QueryCondition {
field: "is_available".to_string(),
operator: QueryOperator::Eq,
value: DataValue::Bool(true),
},
QueryCondition {
field: "price".to_string(),
operator: QueryOperator::Gte,
value: DataValue::Float(300.0),
},
],
),
(
"范围查询",
vec![
QueryCondition {
field: "price".to_string(),
operator: QueryOperator::Gte,
value: DataValue::Float(100.0),
},
QueryCondition {
field: "price".to_string(),
operator: QueryOperator::Lte,
value: DataValue::Float(500.0),
},
],
),
];
for (name, conditions) in test_queries {
let start = Instant::now();
let result = ModelManager::<Product>::find(conditions, None).await?;
let query_time = start.elapsed();
println!("{}: {} 条记录, 耗时 {:?}", name, result.len(), query_time);
}
println!("数据创建耗时: {:?}", create_time);
Ok(())
}
async fn create_performance_test_data(count: usize) -> Result<(), Box<dyn std::error::Error>> {
for i in 0..count {
let user = User {
id: String::new(),
username: format!("perf_user_{}", i),
email: format!("perf{}@test.com", i),
full_name: format!("性能用户 {}", i),
age: Some((25 + i) as i32),
department: match i % 4 {
0 => "技术部".to_string(),
1 => "销售部".to_string(),
2 => "人事部".to_string(),
_ => "财务部".to_string(),
},
is_active: true,
salary: Some(30000.0 + (i as f64 * 100.0)),
created_at: Utc::now(),
updated_at: None,
};
user.save().await?;
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== RatQuickDB MySQL 查询操作完整演示 ===");
LoggerBuilder::new()
.with_level(LevelFilter::Warn)
.add_terminal_with_config(TermConfig::default())
.init()?;
let db_config = DatabaseConfig::builder()
.db_type(DatabaseType::PostgreSQL)
.connection(ConnectionConfig::PostgreSQL {
host: "172.16.0.96".to_string(),
port: 5432,
database: "testdb".to_string(),
username: "testdb".to_string(),
password: "testdb".to_string(),
ssl_mode: Some("prefer".to_string()),
tls_config: Some(rat_quickdb::types::TlsConfig {
enabled: true,
ca_cert_path: None,
client_cert_path: None,
client_key_path: None,
verify_server_cert: false,
verify_hostname: false,
min_tls_version: None,
cipher_suites: None,
}),
})
.pool(
PoolConfig::builder()
.max_connections(1)
.min_connections(1)
.connection_timeout(30)
.idle_timeout(300)
.max_lifetime(3600)
.max_retries(3)
.retry_interval_ms(1000)
.keepalive_interval_sec(60)
.health_check_timeout_sec(10)
.build()?,
)
.alias("main")
.id_strategy(IdStrategy::Uuid)
.build()?;
add_database(db_config).await?;
println!("数据库连接成功");
cleanup_test_data().await;
println!("清理完成");
let batch_stats = demonstrate_batch_operations().await?;
let query_stats = demonstrate_complex_queries().await?;
performance_benchmark().await?;
println!("\n=== 操作统计 ===");
println!("{}", batch_stats.get_summary());
println!("{}", query_stats.get_summary());
println!("\n=== 健康检查 ===");
let health = health_check().await;
for (alias, is_healthy) in health {
let status = if is_healthy { "✅" } else { "❌" };
println!("{}: {}", alias, status);
}
println!("\n演示完成 - 数据保留在数据库中以便检查");
Ok(())
}