From e9baa8d7e0744f36a9f510506ee5900ed4689850 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 5 Apr 2026 20:27:51 +0200 Subject: [PATCH] feat(19-01): update Zod schemas, types, and seed script for reference model - Add globalItemId and purchasePriceCents to createItemSchema - Add globalItemId to createCandidateSchema - Add tags param to searchGlobalItemsSchema - Remove linkItemSchema from schemas and types - Replace ItemGlobalLink with Tag and GlobalItemTag types - Convert seedGlobalItems to async, add seedTags with 30 curated tags --- src/db/seed-global-items.ts | 72 ++++++++++++++++++++++++++++++------- src/shared/schemas.ts | 8 ++--- src/shared/types.ts | 8 ++--- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/db/seed-global-items.ts b/src/db/seed-global-items.ts index 162a801..7ca0f2e 100644 --- a/src/db/seed-global-items.ts +++ b/src/db/seed-global-items.ts @@ -1,27 +1,73 @@ import seedData from "./global-items-seed.json"; import { db as prodDb } from "./index.ts"; -import { globalItems } from "./schema.ts"; +import { globalItems, tags } from "./schema.ts"; type Db = typeof prodDb; +const SEED_TAGS = [ + "handlebar-bag", + "framebag", + "saddlebag", + "top-tube-bag", + "stem-bag", + "fork-bag", + "hip-pack", + "backpack", + "tent", + "bivy", + "tarp", + "hammock", + "sleeping-bag", + "sleeping-pad", + "quilt", + "pillow", + "stove", + "cookware", + "water-filter", + "water-bottle", + "headlamp", + "bike-light", + "ultralight", + "waterproof", + "budget", + "premium", + "bikepacking", + "hiking", + "camping", + "touring", +]; + +/** + * Seed curated tags for outdoor/adventure gear. + * Idempotent: skips if any tags already exist. + */ +export async function seedTags(db: Db = prodDb) { + const existing = await db.select().from(tags).limit(1); + if (existing.length > 0) return; + + for (const name of SEED_TAGS) { + await db.insert(tags).values({ name }); + } +} + /** * Seed the global items table with initial bikepacking gear data. * Idempotent: skips if any rows already exist. */ -export function seedGlobalItems(db: Db = prodDb) { - const existing = db.select().from(globalItems).limit(1).all(); +export async function seedGlobalItems(db: Db = prodDb) { + const existing = await db.select().from(globalItems).limit(1); if (existing.length > 0) return; for (const item of seedData) { - db.insert(globalItems) - .values({ - brand: item.brand, - model: item.model, - category: item.category ?? null, - weightGrams: item.weightGrams ?? null, - priceCents: item.priceCents ?? null, - description: item.description ?? null, - }) - .run(); + await db.insert(globalItems).values({ + brand: item.brand, + model: item.model, + category: item.category ?? null, + weightGrams: item.weightGrams ?? null, + priceCents: item.priceCents ?? null, + description: item.description ?? null, + }); } + + await seedTags(db); } diff --git a/src/shared/schemas.ts b/src/shared/schemas.ts index 0e68b9a..0a02453 100644 --- a/src/shared/schemas.ts +++ b/src/shared/schemas.ts @@ -10,6 +10,8 @@ export const createItemSchema = z.object({ imageFilename: z.string().optional(), imageSourceUrl: z.string().url().optional().or(z.literal("")), quantity: z.number().int().positive().optional(), + globalItemId: z.number().int().positive().optional(), + purchasePriceCents: z.number().int().nonnegative().optional(), }); export const updateItemSchema = createItemSchema.partial().extend({ @@ -58,6 +60,7 @@ export const createCandidateSchema = z.object({ status: candidateStatusSchema.optional(), pros: z.string().optional(), cons: z.string().optional(), + globalItemId: z.number().int().positive().optional(), }); export const updateCandidateSchema = createCandidateSchema.partial(); @@ -95,10 +98,7 @@ export const updateClassificationSchema = z.object({ // Global item schemas export const searchGlobalItemsSchema = z.object({ q: z.string().optional(), -}); - -export const linkItemSchema = z.object({ - globalItemId: z.number().int().positive(), + tags: z.string().optional(), }); // Profile schemas diff --git a/src/shared/types.ts b/src/shared/types.ts index 3069dad..a27d75b 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -2,10 +2,11 @@ import type { z } from "zod"; import type { categories, globalItems, - itemGlobalLinks, + globalItemTags, items, setupItems, setups, + tags, threadCandidates, threads, } from "../db/schema.ts"; @@ -15,7 +16,6 @@ import type { createItemSchema, createSetupSchema, createThreadSchema, - linkItemSchema, reorderCandidatesSchema, resolveThreadSchema, searchGlobalItemsSchema, @@ -49,7 +49,6 @@ export type UpdateClassification = z.infer; // Global item types export type SearchGlobalItems = z.infer; -export type LinkItem = z.infer; export type UpdateProfile = z.infer; // Types inferred from Drizzle schema @@ -60,4 +59,5 @@ export type ThreadCandidate = typeof threadCandidates.$inferSelect; export type Setup = typeof setups.$inferSelect; export type SetupItem = typeof setupItems.$inferSelect; export type GlobalItem = typeof globalItems.$inferSelect; -export type ItemGlobalLink = typeof itemGlobalLinks.$inferSelect; +export type Tag = typeof tags.$inferSelect; +export type GlobalItemTag = typeof globalItemTags.$inferSelect;