Skip to content

Commit 0c10504

Browse files
authored
fix: cleanup maintainers duplicates and prevent them [CM-677] (#3971)
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
1 parent a35c3b0 commit 0c10504

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

backend/src/database/migrations/U1774628604__fixMaintainersInternalUniqueIndex.sql

Whitespace-only changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- Fix maintainersInternal unique index and clean up duplicates.
2+
--
3+
-- Problem:
4+
-- The unique index on ("repoId", "identityId", "startDate", "endDate") fails to
5+
-- prevent duplicates because startDate and endDate are NULL on insert, and
6+
-- PostgreSQL treats NULL != NULL in unique indexes — so the constraint never fires.
7+
--
8+
-- Fix:
9+
-- Unique index on ("repoId", "identityId", role). All three columns are NOT NULL,
10+
-- so the uniqueness check always works. startDate/endDate become purely informational.
11+
12+
-- Step 1: Remove duplicate rows, keeping the most recently updated row per group.
13+
DELETE FROM "maintainersInternal"
14+
WHERE id IN (
15+
SELECT id FROM (
16+
SELECT
17+
id,
18+
ROW_NUMBER() OVER (
19+
PARTITION BY "repoId", "identityId", role
20+
ORDER BY "updatedAt" DESC NULLS LAST, "createdAt" DESC NULLS LAST
21+
) AS rn
22+
FROM "maintainersInternal"
23+
) ranked
24+
WHERE rn > 1
25+
);
26+
27+
-- Step 2: Drop the existing unique index.
28+
DROP INDEX IF EXISTS maintainers_internal_repo_identity_unique_idx;
29+
30+
-- Step 3: Create the correct unique index on non-nullable columns.
31+
CREATE UNIQUE INDEX maintainers_internal_repo_identity_role_unique_idx
32+
ON "maintainersInternal" ("repoId", "identityId", role);

services/apps/git_integration/src/crowdgit/database/crud.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,12 @@ async def upsert_maintainer(
339339
INSERT INTO "maintainersInternal"
340340
("role", "originalRole", "repoUrl", "repoId", "identityId", "startDate", "endDate")
341341
VALUES ($1, $2, $3, $4, $5, $6, $7)
342-
ON CONFLICT ("repoId", "identityId", "startDate", "endDate") DO UPDATE
343-
SET role = EXCLUDED.role, "originalRole" = EXCLUDED."originalRole", "updatedAt" = NOW()
342+
ON CONFLICT ("repoId", "identityId", role) DO UPDATE
343+
SET "originalRole" = EXCLUDED."originalRole",
344+
"repoUrl" = EXCLUDED."repoUrl",
345+
"startDate" = COALESCE("maintainersInternal"."startDate", EXCLUDED."startDate"),
346+
"endDate" = NULL,
347+
"updatedAt" = NOW()
344348
"""
345349
await execute(
346350
sql_query,

0 commit comments

Comments
 (0)