diff --git a/src/lib/db/client-db/index.ts b/src/lib/db/client-db/index.ts index d3f0601..222bd80 100644 --- a/src/lib/db/client-db/index.ts +++ b/src/lib/db/client-db/index.ts @@ -7,5 +7,14 @@ import { SQLocalDrizzle } from "sqlocal/drizzle"; const { driver, batchDriver, overwriteDatabaseFile } = new SQLocalDrizzle( "database.sqlite3", ); + export const db = drizzle(driver, batchDriver); + +/** + * Concrete client DB type (SQLocal-backed Drizzle via sqlite-proxy). + * Exported to allow query helpers to accept the specific type without + * creating circular type references. + */ +export type ClientDb = typeof db; + export { overwriteDatabaseFile }; diff --git a/src/lib/db/client-db/queries.ts b/src/lib/db/client-db/queries.ts index 0a0f2c1..b4d3dc9 100644 --- a/src/lib/db/client-db/queries.ts +++ b/src/lib/db/client-db/queries.ts @@ -1,41 +1,29 @@ import { desc, like } from "drizzle-orm"; import { animeTable } from "$lib/db/schema"; +import type { ClientDb } from "./index"; /** * Client-side DB query helpers (read-only). * - * These functions assume the SQLocal-backed Drizzle `db` is already wired up. - * Seeding/overwriting the database file should be handled separately (see `seed.ts`). + * These functions are intentionally side-effect free — seeding/overwriting the DB + * file should be done separately (see `seed.ts`). * - * Keep these as pure query operations so pages/components can: - * 1) ensure seeded - * 2) query + * We accept the concrete SQLocal-backed Drizzle DB type so callers get full type inference. */ export const DEFAULT_LIST_LIMIT = 20; export const MAX_LIST_LIMIT = 200; -export type AnimeListItem = { - annId: number; - mainName: string; - year: number; - seasonId: number; - malId: number; -}; - /** * Get a short list of anime entries for browsing. * * Sorted by (year desc, seasonId desc, annId desc). */ -export async function getAnimeList( - db: { select: (...args: any[]) => any }, - limit = DEFAULT_LIST_LIMIT, -): Promise { +export async function getAnimeList(db: ClientDb, limit = DEFAULT_LIST_LIMIT) { const safeLimit = clampLimit(limit); - // NOTE: using explicit selection keeps payload small and stable - const rows = await (db as any) + // Explicit selection keeps payload small and gives a stable, inferred return type + return db .select({ annId: animeTable.annId, mainName: animeTable.mainName, @@ -50,8 +38,6 @@ export async function getAnimeList( desc(animeTable.annId), ) .limit(safeLimit); - - return rows as AnimeListItem[]; } /** @@ -61,17 +47,17 @@ export async function getAnimeList( * in the snapshot DB, and querying that instead. */ export async function searchAnimeByName( - db: { select: (...args: any[]) => any }, + db: ClientDb, query: string, limit = DEFAULT_LIST_LIMIT, -): Promise { +) { const q = query.trim(); if (!q) return []; const safeLimit = clampLimit(limit); const pattern = `%${q}%`; - const rows = await (db as any) + return db .select({ annId: animeTable.annId, mainName: animeTable.mainName, @@ -87,8 +73,6 @@ export async function searchAnimeByName( desc(animeTable.annId), ) .limit(safeLimit); - - return rows as AnimeListItem[]; } function clampLimit(limit: number) {