Files
bricktrack/src/db/index.ts
T
unknownandClaude Opus 5 06268bcfd6 feat(db): drizzle-schema, db-client und initiale migration
Vollstaendiges Datenmodell: Katalog (manufacturer, theme, set, tag,
instruction), Besitz (collection_item, location, missing_part, photo),
Wunschlisten (wishlist, wishlist_item) und die Auth-Tabellen von
better-auth inklusive passkey und invite.

Kernregel: ein set ist ein Katalogeintrag, ein collection_item die
Verknuepfung mit dem tatsaechlichen Besitz. Preise liegen als Cent in
INTEGER-Spalten, damit Summen exakt bleiben.

SQLite laeuft mit WAL, foreign_keys=ON und busy_timeout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:25:22 +02:00

42 lines
1.3 KiB
TypeScript

import fs from 'node:fs';
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { env } from '@/env';
import * as schema from './schema';
/**
* SQLite connection for the whole app.
*
* Cached on globalThis so Next's dev-mode module reloading does not open a new
* file handle on every hot reload.
*/
function createConnection() {
fs.mkdirSync(env.DB_DIR, { recursive: true });
const sqlite = new Database(env.DB_PATH);
// WAL keeps readers from blocking the single writer - required for a server
// that renders pages while a background action writes.
sqlite.pragma('journal_mode = WAL');
// NORMAL is the recommended durability level in WAL mode.
sqlite.pragma('synchronous = NORMAL');
// SQLite has foreign keys off by default; our schema relies on them.
sqlite.pragma('foreign_keys = ON');
// Wait instead of throwing SQLITE_BUSY when another write is in flight.
sqlite.pragma('busy_timeout = 5000');
return drizzle(sqlite, { schema });
}
const globalForDb = globalThis as unknown as {
bricktrackDb?: ReturnType<typeof createConnection>;
};
export const db = globalForDb.bricktrackDb ?? createConnection();
if (!env.isProduction) {
globalForDb.bricktrackDb = db;
}
export { schema };
export type Db = typeof db;