fix(db): add migration 0020 for UNIQUE(name) + align admin seed ON CONFLICT
Problem:
- Schema change in eacf8ab added .unique() to services.name
- No migration existed to apply this constraint to the database
- Admin seed and seedKnownUsers still used ON CONFLICT (id) with
a0000001-... IDs, inconsistent with main seed's b0000001-... IDs
and ON CONFLICT (name)
Fix:
- Migration 0020: clean up existing duplicate services (keep lowest
id per name), then add UNIQUE constraint on services.name
- Admin seed (apps/api): switch to ON CONFLICT (name) and b0000001
IDs to match main seed's servicesDef
- seedKnownUsers (packages/db): same alignment — b0000001 IDs and
ON CONFLICT (name)
GRO-364: ON CONFLICT (name) eliminates the duplicate-row problem
that the old dedup+ON CONFLICT(id) approach could not solve when
existing rows had non-deterministic IDs.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
+11
-8
@@ -234,7 +234,8 @@ const productsUsed = [
|
||||
];
|
||||
|
||||
// ── Service definitions ──────────────────────────────────────────────────────
|
||||
// Deterministic service IDs so seed is idempotent (ON CONFLICT targets id, not name).
|
||||
// Deterministic service IDs + UNIQUE(name) constraint make seed fully idempotent:
|
||||
// first run inserts, subsequent runs update existing rows via ON CONFLICT (name).
|
||||
const servicesDef = [
|
||||
{ id: "b0000001-0000-0000-0000-000000000001", name: "Bath & Brush", desc: "Full bath, blow-dry, brush out, and ear cleaning", price: 4500, dur: 45 },
|
||||
{ id: "b0000001-0000-0000-0000-000000000002", name: "Full Groom — Small", desc: "Complete grooming for dogs under 25 lbs", price: 6500, dur: 60 },
|
||||
@@ -293,19 +294,21 @@ async function seedKnownUsers() {
|
||||
console.log("✓ Created staff 'Demo Manager' (oidcSub: demo-manager-001)");
|
||||
}
|
||||
|
||||
// ── Services: idempotent upsert using deterministic IDs ──
|
||||
// ── Services: idempotent upsert using name as unique key ─────────────────────
|
||||
// UNIQUE constraint on services.name (migration 0020) must exist first.
|
||||
// Uses b0000001-... IDs to match main seed servicesDef for same-named services.
|
||||
const demoSvcs = [
|
||||
{ id: "a0000001-0000-0000-0000-000000000001", name: "Bath & Brush", description: "Full bath, blow-dry, brush out, and ear cleaning", basePriceCents: 4500, durationMinutes: 45 },
|
||||
{ id: "a0000001-0000-0000-0000-000000000002", name: "Full Groom — Small", description: "Complete grooming for dogs under 25 lbs", basePriceCents: 6500, durationMinutes: 60 },
|
||||
{ id: "a0000001-0000-0000-0000-000000000003", name: "Full Groom — Medium", description: "Complete grooming for dogs 25-50 lbs", basePriceCents: 8000, durationMinutes: 75 },
|
||||
{ id: "a0000001-0000-0000-0000-000000000004", name: "Nail Trim", description: "Nail clipping and filing", basePriceCents: 1500, durationMinutes: 15 },
|
||||
{ id: "b0000001-0000-0000-0000-000000000001", name: "Bath & Brush", description: "Full bath, blow-dry, brush out, and ear cleaning", basePriceCents: 4500, durationMinutes: 45 },
|
||||
{ id: "b0000001-0000-0000-0000-000000000002", name: "Full Groom — Small", description: "Complete grooming for dogs under 25 lbs", basePriceCents: 6500, durationMinutes: 60 },
|
||||
{ id: "b0000001-0000-0000-0000-000000000003", name: "Full Groom — Medium", description: "Complete grooming for dogs 25-50 lbs", basePriceCents: 8000, durationMinutes: 75 },
|
||||
{ id: "b0000001-0000-0000-0000-000000000004", name: "Nail Trim", description: "Nail clipping and filing", basePriceCents: 1500, durationMinutes: 15 },
|
||||
];
|
||||
for (const svc of demoSvcs) {
|
||||
await db.insert(schema.services)
|
||||
.values({ ...svc, active: true })
|
||||
.onConflictDoUpdate({
|
||||
target: schema.services.id,
|
||||
set: { name: svc.name, description: svc.description, basePriceCents: svc.basePriceCents, durationMinutes: svc.durationMinutes, active: true },
|
||||
target: schema.services.name,
|
||||
set: { description: svc.description, basePriceCents: svc.basePriceCents, durationMinutes: svc.durationMinutes, active: true },
|
||||
});
|
||||
}
|
||||
console.log(`✓ Seeded ${demoSvcs.length} services`);
|
||||
|
||||
Reference in New Issue
Block a user