@@ -12,7 +12,6 @@ use rusqlite::{params, Connection};
1212
1313use crate :: db:: { unix_seconds, Db } ;
1414use crate :: error:: Result ;
15- use crate :: goal_schema:: { CRITERIA_GROUP_SETTLED , MILESTONE_DONE , MILESTONE_IN_PROGRESS , MILESTONE_PENDING } ;
1615
1716// 子模块声明(AGENTS.md §3 单文件 ≤300 行;#[path] 使兄弟文件平铺在同目录,各自带 @ai-context)。
1817/// 里程碑域:里程碑 CRUD + 三写路径共用的插入行 helper。
@@ -27,6 +26,9 @@ mod goal;
2726/// 回顾域:结算快照 / 复习统计 / 成果物清单聚合取数。
2827#[ path = "db_goals_retro.rs" ]
2928mod retro;
29+ /// 绑定域:目标↔组绑定 + 组结算钩子。
30+ #[ path = "db_goals_binding.rs" ]
31+ mod binding;
3032
3133/// 三表 DDL + 索引(幂等:CREATE TABLE IF NOT EXISTS;旧库升级自动补表)。
3234pub ( crate ) fn init ( conn : & Connection ) -> Result < ( ) > {
@@ -81,57 +83,6 @@ pub(crate) fn init(conn: &Connection) -> Result<()> {
8183
8284impl Db {
8385
84- /// 绑定组到目标(UNIQUE 幂等:重复绑定返回 false;组不存在靠外键报错,
85- /// 命令层先行校验)。
86- pub fn bind_group ( & self , goal_id : i64 , group_id : i64 ) -> Result < bool > {
87- self . with_conn ( |conn| {
88- let affected = conn. execute (
89- "INSERT OR IGNORE INTO goal_groups (goal_id, group_id, added_at) VALUES (?1, ?2, ?3)" ,
90- params ! [ goal_id, group_id, unix_seconds( ) ] ,
91- ) ?;
92- Ok ( affected > 0 )
93- } )
94- }
95-
96- /// 解绑组(不影响组本身:组是唯一容器,绑定只是管道)。
97- pub fn unbind_group ( & self , goal_id : i64 , group_id : i64 ) -> Result < bool > {
98- self . with_conn ( |conn| {
99- let affected = conn. execute (
100- "DELETE FROM goal_groups WHERE goal_id = ?1 AND group_id = ?2" ,
101- params ! [ goal_id, group_id] ,
102- ) ?;
103- Ok ( affected > 0 )
104- } )
105- }
106-
107- /// 目标绑定组 id 列表(进度聚合/详情视图数据源)。
108- pub fn list_goal_group_ids ( & self , goal_id : i64 ) -> Result < Vec < i64 > > {
109- self . with_conn ( |conn| {
110- let mut stmt =
111- conn. prepare ( "SELECT group_id FROM goal_groups WHERE goal_id = ?1 ORDER BY id ASC" ) ?;
112- let rows = stmt. query_map ( params ! [ goal_id] , |r| r. get :: < _ , i64 > ( 0 ) ) ?;
113- rows. collect :: < rusqlite:: Result < Vec < _ > > > ( ) . map_err ( Into :: into)
114- } )
115- }
116-
117- /// 组结算钩子(execute_settlement 后调用):绑该组的 group_settled
118- /// 里程碑 pending/in_progress → done(自动通过,进度信号随之生效)。
119- pub fn mark_group_settled_milestones ( & self , group_id : i64 ) -> Result < usize > {
120- let now = unix_seconds ( ) ;
121- self . with_conn ( |conn| {
122- let affected = conn. execute (
123- & format ! (
124- "UPDATE goal_milestones SET status = '{}', completed_at = ?1
125- WHERE criteria_type = '{}' AND ref_group_id = ?2
126- AND status IN ('{}', '{}')" ,
127- MILESTONE_DONE , CRITERIA_GROUP_SETTLED , MILESTONE_PENDING , MILESTONE_IN_PROGRESS
128- ) ,
129- params ! [ now, group_id] ,
130- ) ?;
131- Ok ( affected)
132- } )
133- }
134-
13586 // ─────────────────────── v0.18.1 毕业报告(REQ-255/256) ───────────────────────
13687
13788 /// 写毕业报告快照(目标删除后保留;goal_id SET NULL——报告独立于 goals 行)。
0 commit comments