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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<typeof updateClassificationSchema>;
|
||||
|
||||
// Global item types
|
||||
export type SearchGlobalItems = z.infer<typeof searchGlobalItemsSchema>;
|
||||
export type LinkItem = z.infer<typeof linkItemSchema>;
|
||||
export type UpdateProfile = z.infer<typeof updateProfileSchema>;
|
||||
|
||||
// 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;
|
||||
|
||||
Reference in New Issue
Block a user