rat_quickdb 0.5.2

强大的跨数据库ODM库,支持自动索引创建、统一接口和现代异步架构
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
//! ID策略测试示例
//!
//! 本示例测试不同的ID生成策略是否能正常工作:
//! - AutoIncrement (自增数字)
//! - UUID (字符串)
//! - Snowflake (雪花算法)
//! - ObjectId (MongoDB风格)

use chrono::{DateTime, Utc};
use rat_logger::{LoggerBuilder, debug, handler::term::TermConfig};
use rat_quickdb::types::{ConnectionConfig, DatabaseType, IdStrategy, PoolConfig};
use rat_quickdb::*;
use rat_quickdb::{ModelManager, ModelOperations, datetime_field, integer_field, string_field};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

// 定义测试模型
define_model! {
    /// 测试用户模型
    struct TestUser {
        id: String,
        username: String,
        email: String,
        created_at: DateTime<Utc>,
    }
    collection = "test_users",
    fields = {
        id: string_field(None, None, None).required().unique(),
        username: string_field(None, None, None).required(),
        email: string_field(None, None, None).required(),
        created_at: datetime_field().required(),
    }
    indexes = [
        { fields: ["username"], unique: true, name: "idx_username" },
    ],
}

impl TestUser {
    /// 创建新用户(ID由框架自动生成)
    fn new(username: &str, email: &str) -> Self {
        Self {
            id: String::new(), // 框架会自动替换为正确的ID
            username: username.to_string(),
            email: email.to_string(),
            created_at: Utc::now(),
        }
    }
}

/// 清理测试文件
async fn cleanup_test_files() {
    let test_files = vec![
        "./id_strategy_test.db",
        "./id_strategy_test.db-wal",
        "./id_strategy_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") {
                eprintln!("警告:无法删除测试文件 {}: {}", file, e);
            }
        }
    }
}

/// 测试自增ID策略
async fn test_auto_increment() -> QuickDbResult<()> {
    println!("🔢 测试 AutoIncrement ID 策略");
    println!("===============================");

    // 配置数据库,使用自增ID - 从mysql_array_field_test.rs复制MySQL配置
    let db_config = DatabaseConfig {
        db_type: DatabaseType::MySQL,
        connection: ConnectionConfig::MySQL {
            host: "172.16.0.21".to_string(),
            port: 3306,
            database: "testdb".to_string(),
            username: "testdb".to_string(),
            password: "testdb123456".to_string(),
            ssl_opts: {
                let mut opts = HashMap::new();
                opts.insert("ssl_mode".to_string(), "PREFERRED".to_string());
                Some(opts)
            },
            tls_config: None,
        },
        pool: PoolConfig::builder()
            .min_connections(1)
            .max_connections(5)
            .connection_timeout(30)
            .idle_timeout(300)
            .max_lifetime(1800)
            .max_retries(3)
            .retry_interval_ms(1000)
            .keepalive_interval_sec(60)
            .health_check_timeout_sec(10)
            .build()?,
        alias: "auto_increment_db".to_string(),
        cache: None,
        id_strategy: IdStrategy::AutoIncrement,
    };

    add_database(db_config).await?;

    // 设置默认数据库别名
    rat_quickdb::set_default_alias("auto_increment_db").await?;

    // 清理可能存在的表,避免结构冲突
    let _ = rat_quickdb::drop_table("auto_increment_db", "test_users").await;

    // 创建测试用户
    let users = vec![
        TestUser::new("user1", "user1@test.com"),
        TestUser::new("user2", "user2@test.com"),
        TestUser::new("user3", "user3@test.com"),
    ];

    println!("创建3个用户,测试AutoIncrement策略自动生成ID...");
    let mut created_ids = Vec::new();

    for (i, user) in users.iter().enumerate() {
        match user.save().await {
            Ok(id) => {
                println!("✅ 用户 {} 创建成功,生成的ID: {}", i + 1, id);
                created_ids.push(id);
            }
            Err(e) => {
                println!("❌ 用户 {} 创建失败: {}", i + 1, e);
                return Err(e);
            }
        }
    }

    // 验证ID是否是数字且递增(不能为0)
    println!("\n验证ID是否正确生成:");
    let mut all_valid = true;
    for (i, id) in created_ids.iter().enumerate() {
        println!("用户 {} ID: {} (应该是非零数字且递增)", i + 1, id);
        if let Ok(num_id) = id.parse::<i64>() {
            if num_id > 0 {
                println!("  ✅ ID是有效的正数: {}", num_id);
            } else {
                println!("  ❌ ID为0,说明AutoIncrement策略失败: {}", num_id);
                all_valid = false;
            }
        } else {
            println!("  ❌ ID不是数字: {}", id);
            all_valid = false;
        }
    }

    if all_valid {
        println!("✅ 所有ID验证通过,AutoIncrement策略正常工作");
    } else {
        println!("❌ ID验证失败,AutoIncrement策略有问题");
    }

    // 不清理数据,以便验证实际插入结果
    println!("✅ AutoIncrement ID 测试完成\n");

    Ok(())
}

/// 测试UUID ID策略
async fn test_uuid() -> QuickDbResult<()> {
    println!("🆔 测试 UUID ID 策略");
    println!("========================");

    // 配置数据库,使用UUID ID - 从mysql_array_field_test.rs复制MySQL配置
    let db_config = DatabaseConfig {
        db_type: DatabaseType::MySQL,
        connection: ConnectionConfig::MySQL {
            host: "172.16.0.21".to_string(),
            port: 3306,
            database: "testdb".to_string(),
            username: "testdb".to_string(),
            password: "testdb123456".to_string(),
            ssl_opts: {
                let mut opts = HashMap::new();
                opts.insert("ssl_mode".to_string(), "PREFERRED".to_string());
                Some(opts)
            },
            tls_config: None,
        },
        pool: PoolConfig::builder()
            .min_connections(1)
            .max_connections(5)
            .connection_timeout(30)
            .idle_timeout(300)
            .max_lifetime(1800)
            .max_retries(3)
            .retry_interval_ms(1000)
            .keepalive_interval_sec(60)
            .health_check_timeout_sec(10)
            .build()?,
        alias: "uuid_db".to_string(),
        cache: None,
        id_strategy: IdStrategy::Uuid,
    };

    add_database(db_config).await?;

    // 设置默认数据库别名
    rat_quickdb::set_default_alias("uuid_db").await?;

    // 清理可能存在的表,避免结构冲突
    let _ = rat_quickdb::drop_table("uuid_db", "test_users").await;

    // 创建测试用户
    let users = vec![
        TestUser::new("uuid_user1", "uuid1@test.com"),
        TestUser::new("uuid_user2", "uuid2@test.com"),
        TestUser::new("uuid_user3", "uuid3@test.com"),
    ];

    println!("创建3个用户,测试UUID自动生成...");
    let mut created_ids = Vec::new();

    for (i, user) in users.iter().enumerate() {
        match user.save().await {
            Ok(id) => {
                println!("✅ 用户 {} 创建成功,生成的ID: {}", i + 1, id);
                created_ids.push(id);
            }
            Err(e) => {
                println!("❌ 用户 {} 创建失败: {}", i + 1, e);
                return Err(e);
            }
        }
    }

    // 验证ID是否是有效的UUID
    println!("\n验证ID是否为有效UUID:");
    for (i, id) in created_ids.iter().enumerate() {
        println!("用户 {} ID: {}", i + 1, id);
        if id.len() == 36 {
            println!("  ✅ ID长度正确 (36字符)");
            if id.contains('-') && id.split('-').count() == 5 {
                println!("  ✅ UUID格式正确");
            } else {
                println!("  ❌ UUID格式错误");
            }
        } else {
            println!("  ❌ ID长度错误: {}", id.len());
        }
    }

    // 清理数据
    let _ = rat_quickdb::delete("test_users", vec![], Some("uuid_db")).await;
    println!("✅ UUID ID 测试完成\n");

    Ok(())
}

/// 测试雪花算法ID策略
async fn test_snowflake() -> QuickDbResult<()> {
    println!("❄️ 测试 Snowflake ID 策略");
    println!("=============================");

    // 配置数据库,使用雪花算法ID - 从mysql_array_field_test.rs复制MySQL配置
    let db_config = DatabaseConfig {
        db_type: DatabaseType::MySQL,
        connection: ConnectionConfig::MySQL {
            host: "172.16.0.21".to_string(),
            port: 3306,
            database: "testdb".to_string(),
            username: "testdb".to_string(),
            password: "testdb123456".to_string(),
            ssl_opts: {
                let mut opts = HashMap::new();
                opts.insert("ssl_mode".to_string(), "PREFERRED".to_string());
                Some(opts)
            },
            tls_config: None,
        },
        pool: PoolConfig::builder()
            .min_connections(1)
            .max_connections(5)
            .connection_timeout(30)
            .idle_timeout(300)
            .max_lifetime(1800)
            .max_retries(3)
            .retry_interval_ms(1000)
            .keepalive_interval_sec(60)
            .health_check_timeout_sec(10)
            .build()?,
        alias: "snowflake_db".to_string(),
        cache: None,
        id_strategy: IdStrategy::snowflake(1, 1),
    };

    add_database(db_config).await?;

    // 设置默认数据库别名
    rat_quickdb::set_default_alias("snowflake_db").await?;

    // 清理可能存在的表,避免结构冲突
    let _ = rat_quickdb::drop_table("snowflake_db", "test_users").await;

    // 创建测试用户
    let users = vec![
        TestUser::new("snowflake_user1", "snowflake1@test.com"),
        TestUser::new("snowflake_user2", "snowflake2@test.com"),
        TestUser::new("snowflake_user3", "snowflake3@test.com"),
    ];

    println!("创建3个用户,测试雪花算法ID生成...");
    let mut created_ids = Vec::new();

    for (i, user) in users.iter().enumerate() {
        match user.save().await {
            Ok(id) => {
                println!("✅ 用户 {} 创建成功,生成的ID: {}", i + 1, id);
                created_ids.push(id);
            }
            Err(e) => {
                println!("❌ 用户 {} 创建失败: {}", i + 1, e);
                return Err(e);
            }
        }
    }

    // 验证雪花算法ID
    println!("\n验证雪花算法ID:");
    for (i, id) in created_ids.iter().enumerate() {
        println!("用户 {} ID: {}", i + 1, id);

        // 验证是否为数字
        match id.parse::<u64>() {
            Ok(num_id) => {
                println!("  ✅ ID是有效的64位数字: {}", num_id);

                // 验证是否在合理范围内(Snowflake ID通常是19位数字)
                if id.len() >= 15 && id.len() <= 20 {
                    println!("  ✅ ID长度符合Snowflake标准: {}", id.len());
                } else {
                    println!("  ⚠️  ID长度可能不符合Snowflake标准: {}", id.len());
                }

                // 验证时间戳部分(Snowflake ID的前41位是时间戳)
                let timestamp = num_id >> 22; // 右移22位,取出时间戳部分
                let current_time = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap()
                    .as_millis() as u64;
                let snowflake_epoch = 1288834974657; // Snowflake算法起始时间
                let id_time = timestamp + snowflake_epoch;

                if id_time <= current_time && (current_time - id_time) < 86400000 {
                    // 不超过一天前
                    println!("  ✅ ID时间戳有效: {}", id_time);
                } else {
                    println!("  ⚠️  ID时间戳可能异常: {}", id_time);
                }
            }
            Err(_) => {
                println!("  ❌ ID不是有效的数字: {}", id);
            }
        }
    }

    // 清理数据
    let _ = rat_quickdb::delete("test_users", vec![], Some("snowflake_db")).await;
    println!("✅ Snowflake ID 测试完成\n");

    Ok(())
}

#[tokio::main]
async fn main() -> QuickDbResult<()> {
    // 初始化日志
    LoggerBuilder::new()
        .add_terminal_with_config(TermConfig::default())
        .init()
        .expect("日志初始化失败");

    println!("🧪 RatQuickDB ID策略测试");
    println!("========================\n");

    // 解析命令行参数
    let args: Vec<String> = std::env::args().collect();

    let test_choice = if args.len() == 1 {
        // 没有参数,随机选择一个策略避免污染
        use std::collections::HashMap;
        let strategies = vec!["auto-increment", "uuid", "snowflake"];
        let random_index = (std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos()
            % 3) as usize;
        strategies[random_index]
    } else if args.len() == 2 {
        match args[1].as_str() {
            "--auto-increment" => "auto-increment",
            "--uuid" => "uuid",
            "--snowflake" => "snowflake",
            _ => {
                eprintln!("错误: 未知参数 '{}'", args[1]);
                eprintln!("用法: {} [选项]", args[0]);
                eprintln!("选项:");
                eprintln!("  --auto-increment   运行AutoIncrement策略测试");
                eprintln!("  --uuid             运行UUID策略测试");
                eprintln!("  --snowflake        运行Snowflake策略测试");
                eprintln!("\n  不指定参数时将随机选择一个策略运行");
                return Ok(());
            }
        }
    } else {
        eprintln!("错误: 参数过多");
        eprintln!("用法: {} [选项]", args[0]);
        return Ok(());
    };

    println!("🎯 运行测试策略: {}\n", test_choice);

    // 清理之前的测试文件
    cleanup_test_files().await;

    // 根据选择运行对应的测试
    match test_choice {
        "auto-increment" => {
            test_auto_increment().await?;
        }
        "uuid" => {
            test_uuid().await?;
        }
        "snowflake" => {
            test_snowflake().await?;
        }
        _ => unreachable!(),
    }

    // 清理测试文件
    cleanup_test_files().await;

    println!("🎉 ID策略测试完成!");
    Ok(())
}