Add external_ref UNIQUE constraint and validation
- Add migration for UNIQUE index on external_ref column (bd-897a) - Add validation for duplicate external_ref in batch imports (bd-7315) - Add query planner test to verify index usage (bd-f9a1) - Add concurrent import tests for external_ref (bd-3f6a) The migration detects existing duplicates and fails gracefully. Batch imports now reject duplicates with clear error messages. Tests verify the index is actually used by SQLite query planner. Amp-Thread-ID: https://ampcode.com/threads/T-45ca66ed-3912-46c4-963c-caa7724a9a2f Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -279,3 +279,68 @@ func TestExternalRefIndex(t *testing.T) {
|
||||
t.Error("Expected idx_issues_external_ref index to exist")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExternalRefIndexUsage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s, cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
externalRef := "JIRA-123"
|
||||
issue := &types.Issue{
|
||||
ID: "bd-test-1",
|
||||
Title: "Test issue",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 1,
|
||||
IssueType: types.TypeTask,
|
||||
ExternalRef: &externalRef,
|
||||
}
|
||||
|
||||
err := s.CreateIssue(ctx, issue, "test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create issue: %v", err)
|
||||
}
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT id, title, description, design, acceptance_criteria, notes, status, priority, issue_type, assignee,
|
||||
created_at, updated_at, closed_at, external_ref,
|
||||
compaction_level, compacted_at, compacted_at_commit, original_size
|
||||
FROM issues
|
||||
WHERE external_ref = ?
|
||||
`, externalRef)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get query plan: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var planFound bool
|
||||
var indexUsed bool
|
||||
|
||||
for rows.Next() {
|
||||
var id, parent, notused int
|
||||
var detail string
|
||||
if err := rows.Scan(&id, &parent, ¬used, &detail); err != nil {
|
||||
t.Fatalf("Failed to scan query plan row: %v", err)
|
||||
}
|
||||
planFound = true
|
||||
|
||||
if detail == "SEARCH TABLE issues USING INDEX idx_issues_external_ref (external_ref=?)" ||
|
||||
detail == "SEARCH issues USING INDEX idx_issues_external_ref (external_ref=?)" ||
|
||||
detail == "SEARCH TABLE issues USING INDEX idx_issues_external_ref_unique (external_ref=?)" ||
|
||||
detail == "SEARCH issues USING INDEX idx_issues_external_ref_unique (external_ref=?)" {
|
||||
indexUsed = true
|
||||
}
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Fatalf("Error reading query plan: %v", err)
|
||||
}
|
||||
|
||||
if !planFound {
|
||||
t.Error("Expected query plan output, got none")
|
||||
}
|
||||
|
||||
if !indexUsed {
|
||||
t.Error("Expected query planner to use idx_issues_external_ref index, but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user