105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
/**
|
|
* Seed Quinn shop listings into the quinn.api dev DB.
|
|
* Idempotent: skips listings that already exist (matched by provider_slug + slug).
|
|
* Run: bun run scripts/seed-quinn-shop.ts [path-to-db]
|
|
*/
|
|
|
|
import { Database } from 'bun:sqlite';
|
|
|
|
import { shopListingMigrations } from '../src/entities/shop-listing/schema';
|
|
import { createShopListing, listShopListings } from '../src/entities/shop-listing/repo';
|
|
import { runMigrations, injectDb } from '../src/shared/db';
|
|
import { logger } from '../src/shared/logger';
|
|
import type { ShopListingDraft } from '../src/entities/shop-listing/types';
|
|
|
|
const dbPath =
|
|
process.argv[2] ??
|
|
process.env['DB_PATH'] ??
|
|
new URL('../data/quinn-api-dev.db', import.meta.url).pathname;
|
|
|
|
const db = new Database(dbPath);
|
|
db.exec('PRAGMA journal_mode = WAL');
|
|
db.exec('PRAGMA foreign_keys = ON');
|
|
injectDb(db);
|
|
|
|
runMigrations(db, shopListingMigrations);
|
|
|
|
const PROVIDER = 'quinn';
|
|
|
|
const SEED: ShopListingDraft[] = [
|
|
{
|
|
slug: 'sheer-lace-bodysuit',
|
|
title: 'Sheer Lace Bodysuit',
|
|
description: 'Black sheer lace bodysuit, worn a handful of times. Size S.',
|
|
price: 45,
|
|
currency: 'USD',
|
|
condition: 'like_new',
|
|
category: 'lingerie',
|
|
size: 'S',
|
|
status: 'available',
|
|
photos: [],
|
|
sortOrder: 10,
|
|
providerSlug: PROVIDER,
|
|
},
|
|
{
|
|
slug: 'thigh-high-boots',
|
|
title: 'Thigh-High Boots',
|
|
description: 'Black faux-leather thigh-high boots, size 10. Minimal wear.',
|
|
price: 85,
|
|
currency: 'USD',
|
|
condition: 'good',
|
|
category: 'accessories',
|
|
size: '10',
|
|
status: 'available',
|
|
photos: [],
|
|
sortOrder: 20,
|
|
providerSlug: PROVIDER,
|
|
},
|
|
{
|
|
slug: 'mini-skirt-vinyl',
|
|
title: 'Vinyl Mini Skirt',
|
|
description: 'Glossy vinyl mini skirt. Size M. Perfect for shoots or nights out.',
|
|
price: 35,
|
|
currency: 'USD',
|
|
condition: 'good',
|
|
category: 'clothing',
|
|
size: 'M',
|
|
status: 'available',
|
|
photos: [],
|
|
sortOrder: 30,
|
|
providerSlug: PROVIDER,
|
|
},
|
|
{
|
|
slug: 'e2e-marker',
|
|
title: 'E2E Markerton Item',
|
|
description: 'Synthetic listing used for end-to-end test assertions.',
|
|
price: 1337,
|
|
currency: 'USD',
|
|
condition: 'new',
|
|
category: 'other',
|
|
status: 'available',
|
|
photos: [],
|
|
sortOrder: 999,
|
|
providerSlug: PROVIDER,
|
|
},
|
|
];
|
|
|
|
const existing = listShopListings(db, { providerSlug: PROVIDER });
|
|
const existingSlugs = new Set(existing.map((s) => s.slug));
|
|
|
|
let seeded = 0;
|
|
let skipped = 0;
|
|
|
|
for (const draft of SEED) {
|
|
if (existingSlugs.has(draft.slug)) {
|
|
logger.info('skipping existing shop listing', { slug: draft.slug });
|
|
skipped++;
|
|
continue;
|
|
}
|
|
createShopListing(db, draft);
|
|
logger.info('seeded shop listing', { slug: draft.slug, title: draft.title });
|
|
seeded++;
|
|
}
|
|
|
|
logger.info('seed complete', { seeded, skipped });
|
|
db.close();
|