240 lines
6.6 KiB
Markdown
240 lines
6.6 KiB
Markdown
# 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模式来实际实现测试代码和进行验证。 |