You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ls, ready, blocked, and stats now accept repeated -t flags and apply
AND logic across all specified tags. A shared build_tag_clauses helper
generates the EXISTS SQL clauses. cmd_stats uses indexed JOIN aliases
to avoid ambiguity when filtering on multiple tags.
where_parts.push("t.status NOT IN ('done', 'cancelled')")
130
139
}
131
-
if !tag_filter.is_empty() {
132
-
let tf = sql_escape(tag_filter)
133
-
where_parts.push("EXISTS (SELECT 1 FROM tags tg WHERE tg.task_id = t.id AND tg.tag = '{tf}')")
140
+
for clause in build_tag_clauses(tag_filters) {
141
+
where_parts.push(clause)
134
142
}
135
143
let where_clause = if where_parts.len() == 0 { "" } else { " WHERE {where_parts.join(" AND ")}" }
136
144
let sql = "SELECT t.id, t.title, t.priority, t.status, COALESCE(GROUP_CONCAT(tg.tag, ', '), '') as tags FROM tasks t LEFT JOIN tags tg ON tg.task_id = t.id{where_clause} GROUP BY t.id ORDER BY t.priority ASC, t.created_at ASC"
tag_clause = " AND EXISTS (SELECT 1 FROM tags tg WHERE tg.task_id = t.id AND tg.tag = '{tf}')"
296
+
let tag_clauses = build_tag_clauses(tag_filters)
297
+
if !tag_clauses.is_empty() {
298
+
tag_clause = " AND {tag_clauses.join("AND ")}"
291
299
}
292
300
let sql = "SELECT t.id, t.title, t.priority, t.status, COALESCE(GROUP_CONCAT(tg.tag, ', '), '') as tags FROM tasks t LEFT JOIN tags tg ON tg.task_id = t.id WHERE t.status = 'open' AND NOT EXISTS (SELECT 1 FROM deps d JOIN tasks blocker ON blocker.id = d.blocker_id WHERE d.blocked_id = t.id AND blocker.status NOT IN ('done', 'cancelled')){tag_clause} GROUP BY t.id ORDER BY t.priority ASC, t.created_at ASC"
tag_clause = " AND EXISTS (SELECT 1 FROM tags tg2 WHERE tg2.task_id = t.id AND tg2.tag = '{tf}')"
377
+
let tag_clauses = build_tag_clauses(tag_filters)
378
+
if !tag_clauses.is_empty() {
379
+
tag_clause = " AND {tag_clauses.join("AND ")}"
372
380
}
373
381
let sql = "SELECT t.id, t.title, t.priority, t.status, COALESCE(GROUP_CONCAT(DISTINCT tg.tag), '') as tags, COALESCE(GROUP_CONCAT(DISTINCT d.blocker_id), '') as blockers FROM tasks t JOIN deps d ON d.blocked_id = t.id LEFT JOIN tags tg ON tg.task_id = t.id WHERE t.status NOT IN ('done', 'cancelled'){tag_clause} GROUP BY t.id ORDER BY t.priority ASC"
374
382
let result = db_query(sql)
@@ -440,14 +448,18 @@ pub fn cmd_tags() {
440
448
}
441
449
}
442
450
443
-
pub fn cmd_stats(tag_filter: Str) {
444
-
let mut tag_join = ""
445
-
let mut tag_where = ""
446
-
if !tag_filter.is_empty() {
447
-
let tf = sql_escape(tag_filter)
448
-
tag_join = " JOIN tags tg ON tg.task_id = t.id"
449
-
tag_where = " WHERE tg.tag = '{tf}'"
450
-
}
451
+
pub fn cmd_stats(tag_filters: List[Str]) {
452
+
let mut tag_joins: List[Str] = []
453
+
let mut tag_wheres: List[Str] = []
454
+
let mut ti = 0
455
+
for tag in tag_filters {
456
+
let tf = sql_escape(tag)
457
+
tag_joins.push(" JOIN tags tg{ti} ON tg{ti}.task_id = t.id")
458
+
tag_wheres.push("tg{ti}.tag = '{tf}'")
459
+
ti = ti + 1
460
+
}
461
+
let tag_join = tag_joins.join("")
462
+
let tag_where = if tag_wheres.is_empty() { "" } else { " WHERE {tag_wheres.join(" AND ")}" }
451
463
let result = db_query("SELECT t.status, COUNT(*) as count FROM tasks t{tag_join}{tag_where} GROUP BY t.status ORDER BY t.status")
0 commit comments