- Add classification text column (default 'base') to setupItems schema - Add classificationSchema and updateClassificationSchema Zod validators - Add UpdateClassification type inferred from Zod schema - Implement updateItemClassification service function - Modify getSetupWithItems to return classification field - Modify syncSetupItems to preserve classifications across re-sync - Add tests for classification CRUD, preservation, and cross-setup independence - Generate and apply Drizzle migration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import { Database } from "bun:sqlite";
|
|
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
import * as schema from "../../src/db/schema.ts";
|
|
|
|
export function createTestDb() {
|
|
const sqlite = new Database(":memory:");
|
|
sqlite.run("PRAGMA foreign_keys = ON");
|
|
|
|
// Create tables matching the Drizzle schema
|
|
sqlite.run(`
|
|
CREATE TABLE categories (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
icon TEXT NOT NULL DEFAULT 'package',
|
|
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE items (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
weight_grams REAL,
|
|
price_cents INTEGER,
|
|
category_id INTEGER NOT NULL REFERENCES categories(id),
|
|
notes TEXT,
|
|
product_url TEXT,
|
|
image_filename TEXT,
|
|
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE threads (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
resolved_candidate_id INTEGER,
|
|
category_id INTEGER NOT NULL REFERENCES categories(id),
|
|
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE thread_candidates (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
weight_grams REAL,
|
|
price_cents INTEGER,
|
|
category_id INTEGER NOT NULL REFERENCES categories(id),
|
|
notes TEXT,
|
|
product_url TEXT,
|
|
image_filename TEXT,
|
|
status TEXT NOT NULL DEFAULT 'researching',
|
|
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE setups (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE setup_items (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
setup_id INTEGER NOT NULL REFERENCES setups(id) ON DELETE CASCADE,
|
|
item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
|
|
classification TEXT NOT NULL DEFAULT 'base'
|
|
)
|
|
`);
|
|
|
|
sqlite.run(`
|
|
CREATE TABLE settings (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL
|
|
)
|
|
`);
|
|
|
|
const db = drizzle(sqlite, { schema });
|
|
|
|
// Seed default Uncategorized category
|
|
db.insert(schema.categories)
|
|
.values({ name: "Uncategorized", icon: "package" })
|
|
.run();
|
|
|
|
return db;
|
|
}
|