Files
DevFlow/docs/01-技术文档/SQLite-CRUD模式-2026-06-12.md
绝尘 212a927eee 文档: todo销账(batch29 ARC-05/06+FR-D3+R-PD-10)+待审查登记+DOC整理
- todo: ARC-05越层核验0命中+四领域拆分/ARC-06破环aiShared/FR-D3三子项闭环销账+新增ARC-06b遗留

- 待审查: 登记CR-260616-02(batch29+R-PD-10代码 fc767e1)待审

- DOC-14: df-storage/SQLite-CRUD文档表数V13/V9→V15对齐migrations.rs schema_version=15
2026-06-16 03:28:20 +08:00

3.6 KiB
Raw Blame History

SQLite CRUD 模式

创建: 2026-06-10 | 状态: 初稿


概述

DevFlow 使用 SQLite (rusqlite) 作为本地存储引擎。df-storage 负责 SQLite 连接管理、Schema 迁移和 CRUD 操作。

当前状态

  • SQLite 连接管理: 已实现(Arc<Mutex<Connection>> 单连接,非连接池)
  • Schema 迁移 (V1-V15 累计 14 张表 + 12 索引): 已实现
  • CRUD 层: 已实现(impl_repo! 宏 + 17 个 Repo + 向量检索)

设计要点

已实施内容

  1. impl_repo! 宏 CRUD — 一次性为各表生成 insert / get_by_id / list_all / query / update_field / update_full / delete当前 17 个 Repo非 trait 抽象)
  2. 参数化查询?1/?2 占位符 + params![] 绑定,防止 SQL 注入
  3. 列名白名单校验ALLOWED_COLUMNS 校验 query / update_field 的动态列名
  4. update_full(record) — 整体更新全可变字段(保留 id 与 created_at的原子写
  5. 向量检索 — KnowledgeRepo 余弦相似度 top-N纯 Rust数据量 <50k 暴力遍历)

仍待实施

  1. 泛型 Repository<T> trait — 当前用宏非 trait无统一接口抽象
  2. 事务支持 — 跨表操作的原子性保证(当前单连接 + Mutex无显式事务
  3. 批量操作insert_batch / update_batch

约定

  • ID 字段统一使用 TEXT (UUID v4)
  • 时间字段使用 TEXT (毫秒时间戳字符串,now_millis_str() 返回 String)
  • JSON 字段使用 TEXT 存储 JSON 字符串
  • 所有写操作统一返回 df_core::error::Error 错误类型insert 返 Result<String>idupdate/delete 返 Result<bool>(是否影响行)

update_field 的强制时间戳约束

impl_repo! 宏为各 Repo 统一生成的 update_field(id, field, value) 生成 SQL:

UPDATE {table} SET {field} = ?1, updated_at = ?2 WHERE id = ?3

总是连带刷新 updated_at = now,不可关闭。

适用与不适用

  • 适用:内容更新(标题、状态、描述等)——这些变更本就该反映为新近修改时间。
  • 不适用:纯元数据标记切换(如归档 archived)。归档是元数据,不应改对话的"最近活跃时间",否则侧栏相对时间会跳变为"刚刚"。

例外模式:专用方法走原生 SQL

对元数据类切换,新增专用方法绕过 update_field,直接写原生 SQL 只动目标列。例如 AiConversationRepo::set_archived:

UPDATE ai_conversations SET archived = ?1 WHERE id = ?2

不带 updated_at。

同类专用原生 SQL 方法(均不调 update_field),按「是否刷 updated_at」分两类:

  • 不刷(与 set_archived 同策略,只改目标列):
    • KnowledgeRepo::set_embeddingUPDATE knowledges SET embedding = ?1 WHERE id = ?2(向量写库,非业务修改)
  • (策略相反,刷新时间反映复用行为):
    • KnowledgeRepo::increment_reuse_countUPDATE knowledges SET reuse_count = reuse_count + 1, updated_at = ?1 WHERE id = ?2(原子自增 + 刷时间,因复用确属"近期活跃")

取舍:是否刷 updated_at 取决于语义——元数据/内部字段切换不刷(避免污染相对时间),反映业务行为变更的刷。

相关机制

  • update_full(record):整体更新全可变字段,保留 id 与 created_at,用于 save_conversation 落库对话内容(此时确实要刷 updated_at)。
  • ALLOWED_COLUMNS 白名单:update_field / query 的列名经白名单校验防注入。set_archived 因列名硬编码无需白名单。

相关文件

  • crates/df-storage/src/lib.rs — 存储层入口
  • crates/df-storage/src/migrations.rs — Schema 定义与迁移
  • crates/df-core/src/error.rs — 统一错误类型