diff options
Diffstat (limited to 'src/lib/server/services/groceries.ts')
| -rw-r--r-- | src/lib/server/services/groceries.ts | 286 |
1 files changed, 145 insertions, 141 deletions
diff --git a/src/lib/server/services/groceries.ts b/src/lib/server/services/groceries.ts index c56599c..9f4722b 100644 --- a/src/lib/server/services/groceries.ts +++ b/src/lib/server/services/groceries.ts @@ -1,171 +1,175 @@ -import { db as defaultDb } from '$lib/server/db'; import { groceries, categories, references } from '$lib/server/db/schema'; import { eq, inArray, asc, desc } from 'drizzle-orm'; import { referenceOrder } from './references'; -import type { LibSQLDatabase } from 'drizzle-orm/libsql'; -import type * as schema from '$lib/server/db/schema'; +import type { AppDatabase } from '$lib/server/db/types'; import type { Category, Grocery, Reference } from './types'; -export type AppDatabase = LibSQLDatabase<typeof schema>; - export interface EnrichedGrocery extends Grocery { categoryName: string | null; bestRef: Reference | null; } -export async function loadUnchecked( - db = defaultDb, -): Promise<{ items: EnrichedGrocery[]; categories: Category[] }> { - const [items, cats, refs] = await Promise.all([ - db - .select() - .from(groceries) - .where(eq(groceries.checked, false)) - .orderBy(desc(groceries.createdAt), desc(groceries.id)), - db - .select() - .from(categories) - .orderBy(asc(categories.order), asc(categories.name)), - db - .select() - .from(references) - .orderBy(...referenceOrder), - ]); +function enrichItems( + rawItems: Grocery[], + rawCategories: Category[], + rawReferences: Reference[], +): EnrichedGrocery[] { + const catMap = new Map(rawCategories.map((c) => [c.id, c.name])); + const bestRef = new Map<number, Reference>(); + for (const ref of rawReferences) { + if (!bestRef.has(ref.groceryId)) { + bestRef.set(ref.groceryId, ref); + } + } - return { - items: enrichItems(items, cats, refs), - categories: cats, - }; + return rawItems.map((i) => ({ + ...i, + categoryName: i.categoryId ? (catMap.get(i.categoryId) ?? null) : null, + bestRef: bestRef.get(i.id) ?? null, + })); } -export async function loadAll( - db = defaultDb, -): Promise<{ items: EnrichedGrocery[]; categories: Category[] }> { - const [items, cats, refs] = await Promise.all([ - db - .select() - .from(groceries) - .orderBy(desc(groceries.createdAt), desc(groceries.id)), - db - .select() - .from(categories) - .orderBy(asc(categories.order), asc(categories.name)), - db - .select() - .from(references) - .orderBy(...referenceOrder), - ]); - - return { - items: enrichItems(items, cats, refs), - categories: cats, - }; -} +export class GroceriesService { + constructor(private readonly db: AppDatabase) {} -export async function toggle(id: number, db = defaultDb): Promise<void> { - const [item] = await db.select().from(groceries).where(eq(groceries.id, id)); - if (!item) throw new Error('Grocery not found'); + async loadUnchecked(): Promise<{ + items: EnrichedGrocery[]; + categories: Category[]; + }> { + const [items, cats, refs] = await Promise.all([ + this.db + .select() + .from(groceries) + .where(eq(groceries.checked, false)) + .orderBy(desc(groceries.createdAt), desc(groceries.id)), + this.db + .select() + .from(categories) + .orderBy(asc(categories.order), asc(categories.name)), + this.db + .select() + .from(references) + .orderBy(...referenceOrder), + ]); - await db - .update(groceries) - .set({ checked: !item.checked }) - .where(eq(groceries.id, id)); -} + return { + items: enrichItems(items, cats, refs), + categories: cats, + }; + } -export async function addOrUncheck( - name: string, - categoryId: number | null, - db = defaultDb, -): Promise<{ item: Grocery; created: boolean }> { - const [existing] = await db - .select() - .from(groceries) - .where(eq(groceries.name, name)) - .limit(1); + async loadAll(): Promise<{ + items: EnrichedGrocery[]; + categories: Category[]; + }> { + const [items, cats, refs] = await Promise.all([ + this.db + .select() + .from(groceries) + .orderBy(desc(groceries.createdAt), desc(groceries.id)), + this.db + .select() + .from(categories) + .orderBy(asc(categories.order), asc(categories.name)), + this.db + .select() + .from(references) + .orderBy(...referenceOrder), + ]); - if (existing) { - await db - .update(groceries) - .set({ - checked: false, - categoryId: categoryId ?? existing.categoryId, - }) - .where(eq(groceries.id, existing.id)); return { - item: { - ...existing, - checked: false, - categoryId: categoryId ?? existing.categoryId, - }, - created: false, + items: enrichItems(items, cats, refs), + categories: cats, }; } - const [inserted] = await db - .insert(groceries) - .values({ - name, - categoryId, - createdAt: Temporal.Now.instant().toString({ - smallestUnit: 'millisecond', - }), - }) - .returning(); + async toggle(id: number): Promise<void> { + const [item] = await this.db + .select() + .from(groceries) + .where(eq(groceries.id, id)); + if (!item) throw new Error('Grocery not found'); + + await this.db + .update(groceries) + .set({ checked: !item.checked }) + .where(eq(groceries.id, id)); + } + + async addOrUncheck( + name: string, + categoryId: number | null, + ): Promise<{ item: Grocery; created: boolean }> { + const [existing] = await this.db + .select() + .from(groceries) + .where(eq(groceries.name, name)) + .limit(1); - return { item: inserted, created: true }; -} + if (existing) { + await this.db + .update(groceries) + .set({ + checked: false, + categoryId: categoryId ?? existing.categoryId, + }) + .where(eq(groceries.id, existing.id)); + return { + item: { + ...existing, + checked: false, + categoryId: categoryId ?? existing.categoryId, + }, + created: false, + }; + } -export async function updateGrocery( - id: number, - name: string, - categoryId: number | null, - db = defaultDb, -): Promise<void> { - await db - .update(groceries) - .set({ name, categoryId }) - .where(eq(groceries.id, id)); -} + const [inserted] = await this.db + .insert(groceries) + .values({ + name, + categoryId, + createdAt: Temporal.Now.instant().toString({ + smallestUnit: 'millisecond', + }), + }) + .returning(); -export async function updateGroceryCategory( - id: number, - categoryId: number | null, - db = defaultDb, -): Promise<void> { - await db.update(groceries).set({ categoryId }).where(eq(groceries.id, id)); -} + return { item: inserted, created: true }; + } -export async function bulkUpdateGroceryCategory( - ids: number[], - categoryId: number | null, - db = defaultDb, -): Promise<void> { - await db - .update(groceries) - .set({ categoryId }) - .where(inArray(groceries.id, ids)); -} + async updateGrocery( + id: number, + name: string, + categoryId: number | null, + ): Promise<void> { + await this.db + .update(groceries) + .set({ name, categoryId }) + .where(eq(groceries.id, id)); + } -export async function deleteGrocery(id: number, db = defaultDb): Promise<void> { - await db.delete(groceries).where(eq(groceries.id, id)); -} + async updateGroceryCategory( + id: number, + categoryId: number | null, + ): Promise<void> { + await this.db + .update(groceries) + .set({ categoryId }) + .where(eq(groceries.id, id)); + } -function enrichItems( - rawItems: Grocery[], - rawCategories: Category[], - rawReferences: Reference[], -): EnrichedGrocery[] { - const catMap = new Map(rawCategories.map((c) => [c.id, c.name])); - const bestRef = new Map<number, Reference>(); - for (const ref of rawReferences) { - if (!bestRef.has(ref.groceryId)) { - bestRef.set(ref.groceryId, ref); - } + async bulkUpdateGroceryCategory( + ids: number[], + categoryId: number | null, + ): Promise<void> { + await this.db + .update(groceries) + .set({ categoryId }) + .where(inArray(groceries.id, ids)); } - return rawItems.map((i) => ({ - ...i, - categoryName: i.categoryId ? (catMap.get(i.categoryId) ?? null) : null, - bestRef: bestRef.get(i.id) ?? null, - })); + async deleteGrocery(id: number): Promise<void> { + await this.db.delete(groceries).where(eq(groceries.id, id)); + } } |
