fix(db): use deterministic service IDs and add deduplication step
Replace random uuid() for service IDs with pre-assigned deterministic UUIDs (b0000001-0000-0000-0000-...) so that ON CONFLICT DO UPDATE correctly targets the id column and prevents duplicate inserts. Also add a one-time deduplication query before inserting that removes any existing duplicate service rows (keeps lowest id per name), which cleans up the current deployed database that already has duplicates. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
committed by
Barkley Trimsworth
parent
2fd86d0636
commit
3c5394abef
+20
-16
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
import { drizzle } from "drizzle-orm/postgres-js";
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq, sql } from "drizzle-orm";
|
||||||
import * as schema from "./schema.js";
|
import * as schema from "./schema.js";
|
||||||
|
|
||||||
// ── Deterministic PRNG (Mulberry32) ──────────────────────────────────────────
|
// ── Deterministic PRNG (Mulberry32) ──────────────────────────────────────────
|
||||||
@@ -234,18 +234,18 @@ const productsUsed = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// ── Service definitions ──────────────────────────────────────────────────────
|
// ── Service definitions ──────────────────────────────────────────────────────
|
||||||
|
// Deterministic service IDs so seed is idempotent (ON CONFLICT targets id, not name).
|
||||||
const servicesDef = [
|
const servicesDef = [
|
||||||
{ name: "Bath & Brush", desc: "Full bath, blow-dry, brush out, and ear cleaning", price: 4500, dur: 45 },
|
{ id: "b0000001-0000-0000-0000-000000000001", name: "Bath & Brush", desc: "Full bath, blow-dry, brush out, and ear cleaning", price: 4500, dur: 45 },
|
||||||
{ name: "Full Groom — Small", desc: "Complete grooming for dogs under 25 lbs", price: 6500, dur: 60 },
|
{ id: "b0000001-0000-0000-0000-000000000002", name: "Full Groom — Small", desc: "Complete grooming for dogs under 25 lbs", price: 6500, dur: 60 },
|
||||||
{ name: "Full Groom — Medium", desc: "Complete grooming for dogs 25-50 lbs", price: 8000, dur: 75 },
|
{ id: "b0000001-0000-0000-0000-000000000003", name: "Full Groom — Medium", desc: "Complete grooming for dogs 25-50 lbs", price: 8000, dur: 75 },
|
||||||
{ name: "Full Groom — Large", desc: "Complete grooming for dogs over 50 lbs", price: 9500, dur: 90 },
|
{ id: "b0000001-0000-0000-0000-000000000004", name: "Full Groom — Large", desc: "Complete grooming for dogs over 50 lbs", price: 9500, dur: 90 },
|
||||||
{ name: "Nail Trim", desc: "Nail clipping and filing", price: 1500, dur: 15 },
|
{ id: "b0000001-0000-0000-0000-000000000005", name: "Nail Trim", desc: "Nail clipping and filing", price: 1500, dur: 15 },
|
||||||
{ name: "Teeth Brushing", desc: "Dental cleaning with enzymatic toothpaste", price: 1000, dur: 10 },
|
{ id: "b0000001-0000-0000-0000-000000000006", name: "Teeth Brushing", desc: "Dental cleaning with enzymatic toothpaste", price: 1000, dur: 10 },
|
||||||
{ name: "De-shedding Treatment", desc: "Specialised de-shedding bath and blowout", price: 5500, dur: 60 },
|
{ id: "b0000001-0000-0000-0000-000000000007", name: "De-shedding Treatment", desc: "Specialised de-shedding bath and blowout", price: 5500, dur: 60 },
|
||||||
{ name: "Puppy First Groom", desc: "Gentle introduction to grooming for puppies under 6 months", price: 4000, dur: 30 },
|
{ id: "b0000001-0000-0000-0000-000000000008", name: "Puppy First Groom", desc: "Gentle introduction to grooming for puppies under 6 months", price: 4000, dur: 30 },
|
||||||
{ name: "Flea & Tick Treatment", desc: "Medicated bath with flea and tick shampoo", price: 5000, dur: 45 },
|
{ id: "b0000001-0000-0000-0000-000000000009", name: "Flea & Tick Treatment", desc: "Medicated bath with flea and tick shampoo", price: 5000, dur: 45 },
|
||||||
{ name: "Sanitary Trim", desc: "Hygienic trim of paw pads, face, and sanitary areas", price: 2500, dur: 20 },
|
{ id: "b0000001-0000-0000-0000-00000000000a", name: "Sanitary Trim", desc: "Hygienic trim of paw pads, face, and sanitary areas", price: 2500, dur: 20 },
|
||||||
];
|
];
|
||||||
|
|
||||||
// ── Known-users-only seed (prod/demo) ───────────────────────────────────────
|
// ── Known-users-only seed (prod/demo) ───────────────────────────────────────
|
||||||
@@ -424,13 +424,17 @@ async function seed() {
|
|||||||
console.log(`✓ Created ${allStaff.length} staff (1 manager, 1 receptionist, 3 groomers, 3 bathers)`);
|
console.log(`✓ Created ${allStaff.length} staff (1 manager, 1 receptionist, 3 groomers, 3 bathers)`);
|
||||||
|
|
||||||
// ── Services ──
|
// ── Services ──
|
||||||
const serviceIds: string[] = [];
|
// Deduplicate existing services (keep lowest id per name) before inserting.
|
||||||
|
await db.execute(sql`
|
||||||
|
DELETE FROM services WHERE id NOT IN (
|
||||||
|
SELECT MIN(id) FROM services GROUP BY name
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
for (const s of servicesDef) {
|
for (const s of servicesDef) {
|
||||||
const id = uuid();
|
|
||||||
serviceIds.push(id);
|
|
||||||
await db.insert(schema.services)
|
await db.insert(schema.services)
|
||||||
.values({
|
.values({
|
||||||
id,
|
id: s.id,
|
||||||
name: s.name,
|
name: s.name,
|
||||||
description: s.desc,
|
description: s.desc,
|
||||||
basePriceCents: s.price,
|
basePriceCents: s.price,
|
||||||
|
|||||||
Reference in New Issue
Block a user