Files
GearBox/src/shared/schemas.ts
Jean-Luc Makiola 7a64a1887d feat(10-01): add pros/cons columns through backend
- Add pros/cons nullable TEXT columns to threadCandidates schema
- Generate and apply Drizzle migration (0004_soft_synch.sql)
- Mirror pros/cons columns in test helper CREATE TABLE
- createCandidate: pass pros/cons to values() object
- updateCandidate: add pros/cons to Partial type
- getThreadWithCandidates: include pros/cons in select projection
- createCandidateSchema: add optional pros/cons string fields
2026-03-16 21:32:38 +01:00

85 lines
2.4 KiB
TypeScript

import { z } from "zod";
export const createItemSchema = z.object({
name: z.string().min(1, "Name is required"),
weightGrams: z.number().nonnegative().optional(),
priceCents: z.number().int().nonnegative().optional(),
categoryId: z.number().int().positive(),
notes: z.string().optional(),
productUrl: z.string().url().optional().or(z.literal("")),
imageFilename: z.string().optional(),
});
export const updateItemSchema = createItemSchema.partial().extend({
id: z.number().int().positive(),
});
export const createCategorySchema = z.object({
name: z.string().min(1, "Category name is required"),
icon: z.string().min(1).max(50).default("package"),
});
export const updateCategorySchema = z.object({
id: z.number().int().positive(),
name: z.string().min(1).optional(),
icon: z.string().min(1).max(50).optional(),
});
// Thread schemas
export const createThreadSchema = z.object({
name: z.string().min(1, "Thread name is required"),
categoryId: z.number().int().positive(),
});
export const updateThreadSchema = z.object({
name: z.string().min(1).optional(),
categoryId: z.number().int().positive().optional(),
});
// Candidate status
export const candidateStatusSchema = z.enum([
"researching",
"ordered",
"arrived",
]);
// Candidate schemas (same fields as items)
export const createCandidateSchema = z.object({
name: z.string().min(1, "Name is required"),
weightGrams: z.number().nonnegative().optional(),
priceCents: z.number().int().nonnegative().optional(),
categoryId: z.number().int().positive(),
notes: z.string().optional(),
productUrl: z.string().url().optional().or(z.literal("")),
imageFilename: z.string().optional(),
status: candidateStatusSchema.optional(),
pros: z.string().optional(),
cons: z.string().optional(),
});
export const updateCandidateSchema = createCandidateSchema.partial();
export const resolveThreadSchema = z.object({
candidateId: z.number().int().positive(),
});
// Setup schemas
export const createSetupSchema = z.object({
name: z.string().min(1, "Setup name is required"),
});
export const updateSetupSchema = z.object({
name: z.string().min(1, "Setup name is required"),
});
export const syncSetupItemsSchema = z.object({
itemIds: z.array(z.number().int().positive()),
});
// Classification schemas
export const classificationSchema = z.enum(["base", "worn", "consumable"]);
export const updateClassificationSchema = z.object({
classification: classificationSchema,
});