@@ -9,6 +9,7 @@ import type {
99 EpicListOptions ,
1010 EpicStatus ,
1111 TaskPriority ,
12+ AttachmentMeta ,
1213 SearchQuery ,
1314 SearchResult ,
1415} from '../../types' ;
@@ -38,7 +39,7 @@ export class SqliteEpicsStore implements EpicsStore {
3839 // Helpers
3940 // =========================================================================
4041
41- private toRecord ( row : Record < string , unknown > , tags ?: string [ ] , progress ?: { total : number ; done : number } ) : EpicRecord {
42+ private toRecord ( row : Record < string , unknown > , tags ?: string [ ] , progress ?: { total : number ; done : number } , attachments ?: AttachmentMeta [ ] ) : EpicRecord {
4243 const id = num ( row . id as bigint ) ;
4344 return {
4445 id,
@@ -50,7 +51,7 @@ export class SqliteEpicsStore implements EpicsStore {
5051 tags : tags ?? this . helpers . fetchTags ( GRAPH , id ) ,
5152 order : num ( row . order as bigint | number ) ,
5253 progress : progress ?? this . computeProgress ( id ) ,
53- attachments : this . helpers . fetchAttachments ( GRAPH , id ) ,
54+ attachments : attachments ?? this . helpers . fetchAttachments ( GRAPH , id ) ,
5455 createdAt : num ( row . created_at as bigint ) ,
5556 updatedAt : num ( row . updated_at as bigint ) ,
5657 version : num ( row . version as bigint ) ,
@@ -66,8 +67,8 @@ export class SqliteEpicsStore implements EpicsStore {
6667
6768 private computeProgress ( epicId : number ) : { total : number ; done : number } {
6869 const row = this . db . prepare ( `
69- SELECT COUNT(* ) AS total,
70- COALESCE(SUM(CASE WHEN t.status IN ( 'done', 'cancelled') THEN 1 ELSE 0 END), 0) AS done
70+ SELECT COALESCE(SUM(CASE WHEN t.status != 'cancelled' THEN 1 ELSE 0 END), 0 ) AS total,
71+ COALESCE(SUM(CASE WHEN t.status = 'done' THEN 1 ELSE 0 END), 0) AS done
7172 FROM edges e
7273 JOIN tasks t ON t.id = e.to_id AND t.project_id = e.project_id
7374 WHERE e.project_id = ? AND e.from_graph = 'epics' AND e.from_id = ? AND e.to_graph = 'tasks' AND e.kind = 'belongs_to'
@@ -82,8 +83,9 @@ export class SqliteEpicsStore implements EpicsStore {
8283
8384 const ph = epicIds . map ( ( ) => '?' ) . join ( ',' ) ;
8485 const rows = this . db . prepare ( `
85- SELECT e.from_id AS epic_id, COUNT(*) AS total,
86- COALESCE(SUM(CASE WHEN t.status IN ('done', 'cancelled') THEN 1 ELSE 0 END), 0) AS done
86+ SELECT e.from_id AS epic_id,
87+ COALESCE(SUM(CASE WHEN t.status != 'cancelled' THEN 1 ELSE 0 END), 0) AS total,
88+ COALESCE(SUM(CASE WHEN t.status = 'done' THEN 1 ELSE 0 END), 0) AS done
8789 FROM edges e
8890 JOIN tasks t ON t.id = e.to_id AND t.project_id = e.project_id
8991 WHERE e.project_id = ? AND e.from_graph = 'epics' AND e.to_graph = 'tasks' AND e.kind = 'belongs_to'
@@ -109,7 +111,7 @@ export class SqliteEpicsStore implements EpicsStore {
109111 const result = this . db . prepare ( `
110112 INSERT INTO epics (project_id, slug, title, description, status, priority, "order", version, created_by_id, updated_by_id, created_at, updated_at)
111113 VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)
112- ` ) . run ( this . projectId , slug , data . title , data . description ?? '' , data . status ?? 'open' , data . priority ?? 'medium' , ORDER_GAP , authorId , authorId , ts , ts ) ;
114+ ` ) . run ( this . projectId , slug , data . title , data . description ?? '' , data . status ?? 'open' , data . priority ?? 'medium' , this . nextOrder ( ) , authorId , authorId , ts , ts ) ;
113115 const id = result . lastInsertRowid ;
114116
115117 this . db . prepare ( 'INSERT INTO epics_vec (rowid, embedding) VALUES (?, ?)' ) . run ( BigInt ( id as number | bigint ) , Buffer . from ( new Float32Array ( embedding ) . buffer ) ) ;
@@ -198,9 +200,7 @@ export class SqliteEpicsStore implements EpicsStore {
198200
199201 const results = rows . map ( r => {
200202 const id = num ( r . id as bigint ) ;
201- const record = this . toRecord ( r , tagsMap . get ( id ) , progressMap . get ( id ) ) ;
202- record . attachments = attachMap . get ( id ) ?? [ ] ;
203- return record ;
203+ return this . toRecord ( r , tagsMap . get ( id ) , progressMap . get ( id ) , attachMap . get ( id ) ?? [ ] ) ;
204204 } ) ;
205205
206206 return { results, total } ;
@@ -210,6 +210,11 @@ export class SqliteEpicsStore implements EpicsStore {
210210 return hybridSearch ( this . db , SEARCH_CONFIG , query , this . projectId ) ;
211211 }
212212
213+ private nextOrder ( ) : number {
214+ const row = this . db . prepare ( `SELECT MAX("order") AS m FROM epics WHERE project_id = ?` ) . get ( this . projectId ) as { m : bigint | null } ;
215+ return row . m ? num ( row . m ) + ORDER_GAP : ORDER_GAP ;
216+ }
217+
213218 // =========================================================================
214219 // Link / Unlink tasks
215220 // =========================================================================
0 commit comments