Skip to content

Commit e595af8

Browse files
authored
feat: handle pcc logo url and description (CM-1131) (#4048)
Signed-off-by: Uroš Marolt <uros@marolt.me>
1 parent f7f9693 commit e595af8

1 file changed

Lines changed: 46 additions & 22 deletions

File tree

services/apps/pcc_sync_worker/src/consumer/pccProjectConsumer.ts

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export class PccProjectConsumer {
298298
)
299299
return { action: 'SKIPPED' }
300300
}
301-
segment = fallback as SegmentRow | null
301+
segment = fallback
302302
}
303303

304304
// Step 3: no match → SKIP (Phase 1: project doesn't exist in CDP yet)
@@ -513,7 +513,7 @@ async function upsertSegment(
513513
SET name = $(name),
514514
status = COALESCE($(status)::"segmentsStatus_type", status),
515515
maturity = $(maturity),
516-
description = $(description),
516+
description = COALESCE($(description), description),
517517
"updatedAt" = NOW()
518518
WHERE "sourceId" = $(sourceId) AND "tenantId" = $(tenantId)`,
519519
{
@@ -560,20 +560,31 @@ async function upsertInsightsProject(
560560

561561
// Slug is intentionally not updated — it is a stable identifier referenced by FK from
562562
// securityInsightsEvaluations and related tables.
563-
// logoUrl won't be updated in InsightsProject until we confirm that the format is
564-
// compatible with the Insights Squared standard. Do NOT reintroduce it as a
565-
// `--`-commented SQL line: pg-promise scans placeholders textually and would still
566-
// require the `logoUrl` param, triggering "Property 'logoUrl' doesn't exist".
563+
// description: COALESCE keeps existing when PCC sends null (CM-1131).
564+
// logoUrl: COALESCE("logoUrl", …) never overrides an existing logo; only fills missing ones (CM-1131).
565+
//
566+
// Wrapped in db.tx() so that when called inside an outer transaction (ITask), pg-promise
567+
// creates a SAVEPOINT. A 23505 failure rolls back only the savepoint, leaving the outer
568+
// transaction intact. Without this, a caught PG error still leaves the transaction in
569+
// an aborted state and all subsequent queries on the same tx would fail.
567570
try {
568-
await db.none(
569-
`UPDATE "insightsProjects"
570-
SET name = $(name),
571-
description = $(description),
572-
"updatedAt" = NOW()
573-
WHERE "segmentId" = $(segmentId)
574-
AND "deletedAt" IS NULL`,
575-
{ segmentId, name: project.name, description: project.description },
576-
)
571+
await db.tx(async (t) => {
572+
await t.none(
573+
`UPDATE "insightsProjects"
574+
SET name = $(name),
575+
description = COALESCE($(description), description),
576+
"logoUrl" = COALESCE("logoUrl", $(logoUrl)),
577+
"updatedAt" = NOW()
578+
WHERE "segmentId" = $(segmentId)
579+
AND "deletedAt" IS NULL`,
580+
{
581+
segmentId,
582+
name: project.name,
583+
description: project.description,
584+
logoUrl: project.logoUrl,
585+
},
586+
)
587+
})
577588
} catch (err) {
578589
if (isDuplicateKeyError(err)) return true
579590
throw err
@@ -609,15 +620,28 @@ async function upsertInsightsProject(
609620
)
610621
if (conflicting) return true
611622

612-
// logoUrl intentionally omitted from the INSERT column list — see note above.
623+
// Same savepoint rationale as the UPDATE path above.
613624
try {
614-
await db.none(
615-
`INSERT INTO "insightsProjects" (name, slug, description, "segmentId", "isLF")
616-
VALUES ($(name), generate_slug('insightsProjects', $(name)), $(description), $(segmentId), TRUE)`,
617-
{ name: project.name, description: project.description, segmentId },
618-
)
625+
await db.tx(async (t) => {
626+
await t.none(
627+
`INSERT INTO "insightsProjects" (name, slug, description, "logoUrl", "segmentId", "isLF")
628+
VALUES ($(name), generate_slug('insightsProjects', $(name)), $(description), $(logoUrl), $(segmentId), TRUE)`,
629+
{
630+
name: project.name,
631+
description: project.description,
632+
logoUrl: project.logoUrl,
633+
segmentId,
634+
},
635+
)
636+
})
619637
} catch (err) {
620-
if (isDuplicateKeyError(err)) return true
638+
if (isDuplicateKeyError(err)) {
639+
// unique_project_segmentId: another worker already inserted a row for this segment
640+
// concurrently — treat as "already represented", no conflict to record.
641+
const constraintName = (err as { constraint?: string }).constraint
642+
if (constraintName === 'unique_project_segmentId') return false
643+
return true
644+
}
621645
throw err
622646
}
623647
return false

0 commit comments

Comments
 (0)