Files
task-master/internal/sqlite/backfill_keys.go
T
skrueckenandCursor efeb4a74a8 Assign readable ticket keys from project code and sequence.
Replace UUID-looking sync labels in TUI and web with keys like TAS-1,
while keeping the remote UUID for task-master matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-28 00:09:14 +01:00

132 lines
2.8 KiB
Go

package sqlite
import (
"database/sql"
"fmt"
)
// backfillTicketKeys assigns project codes and sequential ticket keys for rows
// that predate migration 005. Safe to run repeatedly (no-ops when already set).
func (db *DB) backfillTicketKeys() error {
if err := db.backfillProjectCodes(); err != nil {
return err
}
return db.backfillTicketNumbers()
}
func (db *DB) backfillProjectCodes() error {
rows, err := db.SQL.Query(`SELECT id, name, code FROM projects`)
if err != nil {
return fmt.Errorf("backfill codes: list: %w", err)
}
defer rows.Close()
type row struct {
id, name, code string
}
var all []row
used := map[string]bool{}
for rows.Next() {
var r row
if err := rows.Scan(&r.id, &r.name, &r.code); err != nil {
return err
}
all = append(all, r)
if r.code != "" {
used[r.code] = true
}
}
if err := rows.Err(); err != nil {
return err
}
for _, r := range all {
if r.code != "" {
continue
}
code := nextUniqueCode(r.name, used)
used[code] = true
if _, err := db.SQL.Exec(`UPDATE projects SET code = ? WHERE id = ?`, code, r.id); err != nil {
return fmt.Errorf("backfill code %s: %w", r.id, err)
}
}
return nil
}
func (db *DB) backfillTicketNumbers() error {
type proj struct {
id, code string
seq int
}
var projects []proj
{
projRows, err := db.SQL.Query(`SELECT id, code, ticket_seq FROM projects`)
if err != nil {
return fmt.Errorf("backfill tickets: projects: %w", err)
}
for projRows.Next() {
var p proj
if err := projRows.Scan(&p.id, &p.code, &p.seq); err != nil {
projRows.Close()
return err
}
projects = append(projects, p)
}
err = projRows.Err()
projRows.Close()
if err != nil {
return err
}
}
for _, p := range projects {
type trow struct {
id, key string
number sql.NullInt64
}
var tickets []trow
{
tRows, err := db.SQL.Query(`
SELECT id, number, key FROM tickets
WHERE project_id = ?
ORDER BY created_at ASC, id ASC`, p.id)
if err != nil {
return err
}
for tRows.Next() {
var tr trow
if err := tRows.Scan(&tr.id, &tr.number, &tr.key); err != nil {
tRows.Close()
return err
}
tickets = append(tickets, tr)
}
err = tRows.Err()
tRows.Close()
if err != nil {
return err
}
}
seq := p.seq
for _, tr := range tickets {
if tr.number.Valid && tr.key != "" {
if int(tr.number.Int64) > seq {
seq = int(tr.number.Int64)
}
continue
}
seq++
newKey := fmt.Sprintf("%s-%d", p.code, seq)
if _, err := db.SQL.Exec(`UPDATE tickets SET number = ?, key = ? WHERE id = ?`, seq, newKey, tr.id); err != nil {
return fmt.Errorf("backfill ticket %s: %w", tr.id, err)
}
}
if seq != p.seq {
if _, err := db.SQL.Exec(`UPDATE projects SET ticket_seq = ? WHERE id = ?`, seq, p.id); err != nil {
return err
}
}
}
return nil
}