fix(sqlite): update child_counters when explicit child IDs are created (GH#728)
When creating issues with explicit hierarchical IDs (e.g., bd-test.1, bd-test.2 via --id flag or import), the child_counters table was not being updated. This caused GetNextChildID to return colliding IDs when later called with --parent. Changes: - Add ensureChildCounterUpdatedWithConn() to update counter on explicit child creation - Add ParseHierarchicalID() to extract parent and child number from IDs - Update CreateIssue to call counter update after hierarchical ID validation - Update EnsureIDs to call counter update when parent exists - Add post-insert phase in batch operations to update counters after FK constraint can be satisfied - Update tests to reflect new behavior where counter is properly initialized 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,30 @@ func bulkMarkDirty(ctx context.Context, conn *sql.Conn, issues []*types.Issue) e
|
||||
return markDirtyBatch(ctx, conn, issues)
|
||||
}
|
||||
|
||||
// updateChildCountersForHierarchicalIDs updates child_counters for all hierarchical IDs in the batch.
|
||||
// This is called AFTER issues are inserted so that parents exist for the foreign key constraint.
|
||||
// (GH#728 fix)
|
||||
func updateChildCountersForHierarchicalIDs(ctx context.Context, conn *sql.Conn, issues []*types.Issue) error {
|
||||
for _, issue := range issues {
|
||||
if issue.ID == "" {
|
||||
continue // Skip issues that were filtered out (e.g., OrphanSkip)
|
||||
}
|
||||
if parentID, childNum, ok := ParseHierarchicalID(issue.ID); ok {
|
||||
// Only update if parent exists (it should after insert, but check to be safe)
|
||||
var parentCount int
|
||||
if err := conn.QueryRowContext(ctx, `SELECT COUNT(*) FROM issues WHERE id = ?`, parentID).Scan(&parentCount); err != nil {
|
||||
return fmt.Errorf("failed to check parent existence for %s: %w", parentID, err)
|
||||
}
|
||||
if parentCount > 0 {
|
||||
if err := ensureChildCounterUpdatedWithConn(ctx, conn, parentID, childNum); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkForExistingIDs verifies that:
|
||||
// 1. There are no duplicate IDs within the batch itself
|
||||
// 2. None of the issue IDs already exist in the database
|
||||
@@ -271,6 +295,12 @@ func (s *SQLiteStorage) CreateIssuesWithFullOptions(ctx context.Context, issues
|
||||
return wrapDBError("bulk insert issues", err)
|
||||
}
|
||||
|
||||
// Phase 4.5: Update child counters for hierarchical IDs (GH#728 fix)
|
||||
// This must happen AFTER insert so parents exist for the foreign key constraint
|
||||
if err := updateChildCountersForHierarchicalIDs(ctx, conn, issues); err != nil {
|
||||
return wrapDBError("update child counters", err)
|
||||
}
|
||||
|
||||
// Phase 5: Record creation events
|
||||
if err := bulkRecordEvents(ctx, conn, issues, actor); err != nil {
|
||||
return wrapDBError("record creation events", err)
|
||||
|
||||
Reference in New Issue
Block a user