bd sync: 2025-12-27 15:56:42

This commit is contained in:
Steve Yegge
2025-12-27 15:56:42 -08:00
parent 87f535a65e
commit c8b912cbe6
179 changed files with 3051 additions and 10283 deletions

View File

@@ -21,177 +21,138 @@ import (
func MigrateEdgeFields(db *sql.DB) error {
now := time.Now()
hasColumn := func(name string) (bool, error) {
var exists bool
err := db.QueryRow(`
SELECT COUNT(*) > 0
FROM pragma_table_info('issues')
WHERE name = ?
`, name).Scan(&exists)
return exists, err
}
hasRepliesTo, err := hasColumn("replies_to")
if err != nil {
return fmt.Errorf("failed to check replies_to column: %w", err)
}
hasRelatesTo, err := hasColumn("relates_to")
if err != nil {
return fmt.Errorf("failed to check relates_to column: %w", err)
}
hasDuplicateOf, err := hasColumn("duplicate_of")
if err != nil {
return fmt.Errorf("failed to check duplicate_of column: %w", err)
}
hasSupersededBy, err := hasColumn("superseded_by")
if err != nil {
return fmt.Errorf("failed to check superseded_by column: %w", err)
}
if !hasRepliesTo && !hasRelatesTo && !hasDuplicateOf && !hasSupersededBy {
return nil
}
// Migrate replies_to fields to replies-to edges
// For thread_id, use the parent's ID as the thread root for first-level replies
// (more sophisticated thread detection would require recursive queries)
if hasRepliesTo {
rows, err := db.Query(`
SELECT id, replies_to
FROM issues
WHERE replies_to != '' AND replies_to IS NOT NULL
`)
rows, err := db.Query(`
SELECT id, replies_to
FROM issues
WHERE replies_to != '' AND replies_to IS NOT NULL
`)
if err != nil {
return fmt.Errorf("failed to query replies_to fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, repliesTo string
if err := rows.Scan(&issueID, &repliesTo); err != nil {
return fmt.Errorf("failed to scan replies_to row: %w", err)
}
// Use repliesTo as thread_id (the root of the thread)
// This is a simplification - existing threads will have the parent as thread root
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'replies-to', ?, 'migration', '{}', ?)
`, issueID, repliesTo, now, repliesTo)
if err != nil {
return fmt.Errorf("failed to query replies_to fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, repliesTo string
if err := rows.Scan(&issueID, &repliesTo); err != nil {
return fmt.Errorf("failed to scan replies_to row: %w", err)
}
// Use repliesTo as thread_id (the root of the thread)
// This is a simplification - existing threads will have the parent as thread root
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'replies-to', ?, 'migration', '{}', ?)
`, issueID, repliesTo, now, repliesTo)
if err != nil {
return fmt.Errorf("failed to create replies-to edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating replies_to rows: %w", err)
return fmt.Errorf("failed to create replies-to edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating replies_to rows: %w", err)
}
// Migrate relates_to fields to relates-to edges
// relates_to is stored as JSON array string
if hasRelatesTo {
rows, err := db.Query(`
SELECT id, relates_to
FROM issues
WHERE relates_to != '' AND relates_to != '[]' AND relates_to IS NOT NULL
`)
if err != nil {
return fmt.Errorf("failed to query relates_to fields: %w", err)
rows, err = db.Query(`
SELECT id, relates_to
FROM issues
WHERE relates_to != '' AND relates_to != '[]' AND relates_to IS NOT NULL
`)
if err != nil {
return fmt.Errorf("failed to query relates_to fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, relatesTo string
if err := rows.Scan(&issueID, &relatesTo); err != nil {
return fmt.Errorf("failed to scan relates_to row: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, relatesTo string
if err := rows.Scan(&issueID, &relatesTo); err != nil {
return fmt.Errorf("failed to scan relates_to row: %w", err)
}
// Parse JSON array
var relatedIDs []string
if err := json.Unmarshal([]byte(relatesTo), &relatedIDs); err != nil {
// Skip malformed JSON
continue
}
// Parse JSON array
var relatedIDs []string
if err := json.Unmarshal([]byte(relatesTo), &relatedIDs); err != nil {
// Skip malformed JSON
for _, relatedID := range relatedIDs {
if relatedID == "" {
continue
}
for _, relatedID := range relatedIDs {
if relatedID == "" {
continue
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'relates-to', ?, 'migration', '{}', '')
`, issueID, relatedID, now)
if err != nil {
return fmt.Errorf("failed to create relates-to edge for %s -> %s: %w", issueID, relatedID, err)
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'relates-to', ?, 'migration', '{}', '')
`, issueID, relatedID, now)
if err != nil {
return fmt.Errorf("failed to create relates-to edge for %s -> %s: %w", issueID, relatedID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating relates_to rows: %w", err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating relates_to rows: %w", err)
}
// Migrate duplicate_of fields to duplicates edges
if hasDuplicateOf {
rows, err := db.Query(`
SELECT id, duplicate_of
FROM issues
WHERE duplicate_of != '' AND duplicate_of IS NOT NULL
`)
rows, err = db.Query(`
SELECT id, duplicate_of
FROM issues
WHERE duplicate_of != '' AND duplicate_of IS NOT NULL
`)
if err != nil {
return fmt.Errorf("failed to query duplicate_of fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, duplicateOf string
if err := rows.Scan(&issueID, &duplicateOf); err != nil {
return fmt.Errorf("failed to scan duplicate_of row: %w", err)
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'duplicates', ?, 'migration', '{}', '')
`, issueID, duplicateOf, now)
if err != nil {
return fmt.Errorf("failed to query duplicate_of fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, duplicateOf string
if err := rows.Scan(&issueID, &duplicateOf); err != nil {
return fmt.Errorf("failed to scan duplicate_of row: %w", err)
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'duplicates', ?, 'migration', '{}', '')
`, issueID, duplicateOf, now)
if err != nil {
return fmt.Errorf("failed to create duplicates edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating duplicate_of rows: %w", err)
return fmt.Errorf("failed to create duplicates edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating duplicate_of rows: %w", err)
}
// Migrate superseded_by fields to supersedes edges
if hasSupersededBy {
rows, err := db.Query(`
SELECT id, superseded_by
FROM issues
WHERE superseded_by != '' AND superseded_by IS NOT NULL
`)
rows, err = db.Query(`
SELECT id, superseded_by
FROM issues
WHERE superseded_by != '' AND superseded_by IS NOT NULL
`)
if err != nil {
return fmt.Errorf("failed to query superseded_by fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, supersededBy string
if err := rows.Scan(&issueID, &supersededBy); err != nil {
return fmt.Errorf("failed to scan superseded_by row: %w", err)
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'supersedes', ?, 'migration', '{}', '')
`, issueID, supersededBy, now)
if err != nil {
return fmt.Errorf("failed to query superseded_by fields: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID, supersededBy string
if err := rows.Scan(&issueID, &supersededBy); err != nil {
return fmt.Errorf("failed to scan superseded_by row: %w", err)
}
_, err := db.Exec(`
INSERT OR IGNORE INTO dependencies (issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id)
VALUES (?, ?, 'supersedes', ?, 'migration', '{}', '')
`, issueID, supersededBy, now)
if err != nil {
return fmt.Errorf("failed to create supersedes edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating superseded_by rows: %w", err)
return fmt.Errorf("failed to create supersedes edge for %s: %w", issueID, err)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("error iterating superseded_by rows: %w", err)
}
return nil
}