feat: 实现数据库迁移、搜索和分页功能
- 添加数据库迁移系统和初始用户表迁移 - 实现搜索功能模块和API - 实现分页功能支持 - 添加相关测试文件 - 更新项目配置和文档
This commit is contained in:
240
database_verification_plan.md
Normal file
240
database_verification_plan.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# SQLite 数据库存储功能验证计划
|
||||
|
||||
## 📋 当前状态分析
|
||||
|
||||
### ✅ 已实现的功能
|
||||
根据代码分析,SQLite数据库存储已经基本实现:
|
||||
|
||||
1. **数据库连接**: [`src/storage/database.rs`](src/storage/database.rs) 实现了完整的SQLite存储层
|
||||
2. **表结构**: 自动创建users表,包含所有必要字段
|
||||
3. **CRUD操作**: 实现了所有用户管理操作
|
||||
4. **错误处理**: 包含数据库特定的错误处理
|
||||
5. **配置支持**: [`src/main.rs`](src/main.rs) 支持通过环境变量切换存储类型
|
||||
|
||||
### 🔍 需要验证的功能点
|
||||
|
||||
#### 1. 数据库连接和初始化
|
||||
- [ ] 验证SQLite数据库文件创建
|
||||
- [ ] 验证表结构正确创建
|
||||
- [ ] 验证连接池正常工作
|
||||
|
||||
#### 2. CRUD操作完整性
|
||||
- [ ] 创建用户功能
|
||||
- [ ] 读取用户功能(按ID和用户名)
|
||||
- [ ] 更新用户功能
|
||||
- [ ] 删除用户功能
|
||||
- [ ] 列出所有用户功能
|
||||
|
||||
#### 3. 数据一致性和约束
|
||||
- [ ] 用户名唯一性约束
|
||||
- [ ] 数据类型转换正确性
|
||||
- [ ] 时间戳处理正确性
|
||||
- [ ] UUID处理正确性
|
||||
|
||||
#### 4. 错误处理
|
||||
- [ ] 重复用户名错误处理
|
||||
- [ ] 数据库连接错误处理
|
||||
- [ ] 数据格式错误处理
|
||||
|
||||
## 🧪 验证方法
|
||||
|
||||
### 方法1: 单元测试验证
|
||||
创建专门的数据库测试文件 `tests/database_tests.rs`:
|
||||
|
||||
```rust
|
||||
//! SQLite 数据库存储测试
|
||||
|
||||
use rust_user_api::{
|
||||
models::user::User,
|
||||
storage::{database::DatabaseUserStore, UserStore},
|
||||
utils::errors::ApiError,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
use chrono::Utc;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_database_crud_operations() {
|
||||
// 创建临时数据库
|
||||
let temp_dir = tempdir().expect("Failed to create temp directory");
|
||||
let db_path = temp_dir.path().join("test.db");
|
||||
let database_url = format!("sqlite://{}", db_path.display());
|
||||
|
||||
let store = DatabaseUserStore::from_url(&database_url)
|
||||
.await
|
||||
.expect("Failed to create database store");
|
||||
|
||||
// 测试创建用户
|
||||
let user = User {
|
||||
id: Uuid::new_v4(),
|
||||
username: "dbtest".to_string(),
|
||||
email: "dbtest@example.com".to_string(),
|
||||
password_hash: "hashed_password".to_string(),
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
};
|
||||
|
||||
let created_user = store.create_user(user.clone()).await.unwrap();
|
||||
assert_eq!(created_user.username, "dbtest");
|
||||
|
||||
// 测试读取用户
|
||||
let retrieved_user = store.get_user(&user.id).await.unwrap();
|
||||
assert!(retrieved_user.is_some());
|
||||
|
||||
// 测试按用户名读取
|
||||
let user_by_name = store.get_user_by_username("dbtest").await.unwrap();
|
||||
assert!(user_by_name.is_some());
|
||||
|
||||
// 测试更新用户
|
||||
let mut updated_user = user.clone();
|
||||
updated_user.username = "updated_dbtest".to_string();
|
||||
let update_result = store.update_user(&user.id, updated_user).await.unwrap();
|
||||
assert!(update_result.is_some());
|
||||
|
||||
// 测试删除用户
|
||||
let delete_result = store.delete_user(&user.id).await.unwrap();
|
||||
assert!(delete_result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_database_constraints() {
|
||||
let temp_dir = tempdir().expect("Failed to create temp directory");
|
||||
let db_path = temp_dir.path().join("test_constraints.db");
|
||||
let database_url = format!("sqlite://{}", db_path.display());
|
||||
|
||||
let store = DatabaseUserStore::from_url(&database_url)
|
||||
.await
|
||||
.expect("Failed to create database store");
|
||||
|
||||
// 创建第一个用户
|
||||
let user1 = User {
|
||||
id: Uuid::new_v4(),
|
||||
username: "duplicate_test".to_string(),
|
||||
email: "test1@example.com".to_string(),
|
||||
password_hash: "hashed_password".to_string(),
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
};
|
||||
|
||||
store.create_user(user1).await.unwrap();
|
||||
|
||||
// 尝试创建相同用户名的用户
|
||||
let user2 = User {
|
||||
id: Uuid::new_v4(),
|
||||
username: "duplicate_test".to_string(), // 相同用户名
|
||||
email: "test2@example.com".to_string(),
|
||||
password_hash: "hashed_password".to_string(),
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
};
|
||||
|
||||
let result = store.create_user(user2).await;
|
||||
assert!(result.is_err());
|
||||
|
||||
if let Err(ApiError::Conflict(msg)) = result {
|
||||
assert!(msg.contains("用户名已存在"));
|
||||
} else {
|
||||
panic!("Expected Conflict error for duplicate username");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方法2: 集成测试验证
|
||||
修改现有的集成测试,添加数据库模式测试:
|
||||
|
||||
1. 设置环境变量 `DATABASE_URL=sqlite://test_integration.db`
|
||||
2. 运行现有的集成测试
|
||||
3. 验证数据持久化到数据库文件
|
||||
|
||||
### 方法3: 手动验证
|
||||
1. 创建 `.env` 文件,启用数据库模式
|
||||
2. 启动服务器
|
||||
3. 使用API创建用户
|
||||
4. 重启服务器
|
||||
5. 验证用户数据仍然存在
|
||||
|
||||
## 🔧 需要添加的依赖
|
||||
|
||||
在 `Cargo.toml` 的 `[dev-dependencies]` 中添加:
|
||||
|
||||
```toml
|
||||
tempfile = "3.0" # 用于创建临时测试数据库
|
||||
```
|
||||
|
||||
## 📝 验证步骤
|
||||
|
||||
### 步骤1: 添加数据库测试
|
||||
- 创建 `tests/database_tests.rs`
|
||||
- 添加tempfile依赖
|
||||
- 实现数据库CRUD测试
|
||||
- 实现约束测试
|
||||
|
||||
### 步骤2: 运行测试验证
|
||||
```bash
|
||||
# 运行数据库测试
|
||||
cargo test database_tests
|
||||
|
||||
# 运行所有测试
|
||||
cargo test
|
||||
```
|
||||
|
||||
### 步骤3: 集成测试验证
|
||||
```bash
|
||||
# 设置数据库环境变量
|
||||
export DATABASE_URL=sqlite://test_integration.db
|
||||
|
||||
# 启动服务器
|
||||
cargo run
|
||||
|
||||
# 在另一个终端运行集成测试
|
||||
cargo test integration_tests
|
||||
```
|
||||
|
||||
### 步骤4: 手动功能验证
|
||||
1. 创建 `.env` 文件:
|
||||
```env
|
||||
DATABASE_URL=sqlite://users.db
|
||||
```
|
||||
|
||||
2. 启动服务器并测试API
|
||||
3. 检查数据库文件是否创建
|
||||
4. 重启服务器验证数据持久化
|
||||
|
||||
## 🚨 可能遇到的问题
|
||||
|
||||
### 问题1: 数据库文件权限
|
||||
**症状**: 无法创建或写入数据库文件
|
||||
**解决方案**: 确保应用有写入权限,使用绝对路径
|
||||
|
||||
### 问题2: SQLite版本兼容性
|
||||
**症状**: SQL语法错误或功能不支持
|
||||
**解决方案**: 检查SQLite版本,更新SQL语句
|
||||
|
||||
### 问题3: 连接池配置
|
||||
**症状**: 并发访问时出现连接错误
|
||||
**解决方案**: 配置适当的连接池大小
|
||||
|
||||
### 问题4: 数据类型转换
|
||||
**症状**: UUID或时间戳存储/读取错误
|
||||
**解决方案**: 检查数据类型转换逻辑
|
||||
|
||||
## ✅ 验证完成标准
|
||||
|
||||
数据库存储功能验证完成的标准:
|
||||
|
||||
1. ✅ 所有数据库单元测试通过
|
||||
2. ✅ 集成测试在数据库模式下通过
|
||||
3. ✅ 手动验证数据持久化正常
|
||||
4. ✅ 错误处理机制正常工作
|
||||
5. ✅ 性能测试满足要求
|
||||
|
||||
## 📋 下一步行动
|
||||
|
||||
完成数据库验证后,继续TODO列表中的下一项:
|
||||
- 添加数据库迁移系统
|
||||
- 实现数据库连接池配置
|
||||
- 添加API分页功能
|
||||
|
||||
---
|
||||
|
||||
**注意**: 这个验证计划需要切换到Code模式来实际实现测试代码和进行验证。
|
Reference in New Issue
Block a user