fooder-app/src/lib/offline/db.ts
2026-04-02 09:37:44 +02:00

88 lines
2.9 KiB
TypeScript

import { openDB, type IDBPDatabase } from 'idb';
import type { Diary, Product } from '$lib/types/api';
const DB_NAME = 'fooder';
const DB_VERSION = 2;
export interface QueuedMutation {
id?: number;
method: 'POST' | 'PATCH' | 'DELETE';
url: string;
body: unknown;
createdAt: number;
}
let dbInstance: IDBPDatabase | null = null;
export async function getDb() {
if (dbInstance) return dbInstance;
dbInstance = await openDB(DB_NAME, DB_VERSION, {
upgrade(db, oldVersion) {
if (oldVersion < 1) {
db.createObjectStore('diaries', { keyPath: 'date' });
db.createObjectStore('mutation_queue', { keyPath: 'id', autoIncrement: true });
}
if (oldVersion < 2) {
if (!db.objectStoreNames.contains('products')) {
db.createObjectStore('products', { keyPath: 'id' });
}
}
}
});
return dbInstance;
}
// ── Diary cache ──────────────────────────────────────────────────────────────
export async function cacheDiary(diary: Diary): Promise<void> {
const db = await getDb();
await db.put('diaries', diary);
}
export async function getCachedDiary(date: string): Promise<Diary | undefined> {
const db = await getDb();
return db.get('diaries', date);
}
// ── Product cache ─────────────────────────────────────────────────────────────
export async function cacheProducts(products: Product[]): Promise<void> {
if (products.length === 0) return;
const db = await getDb();
const tx = db.transaction('products', 'readwrite');
await Promise.all(products.map(p => tx.store.put(p)));
await tx.done;
}
export async function searchCachedProducts(q: string): Promise<Product[]> {
const db = await getDb();
const all = await db.getAll('products');
if (!q.trim()) return all.slice(0, 30);
const lower = q.toLowerCase();
return all
.filter(p => p.name.toLowerCase().includes(lower))
.sort((a, b) => (b.usage_count_cached ?? 0) - (a.usage_count_cached ?? 0))
.slice(0, 30);
}
// ── Mutation queue ────────────────────────────────────────────────────────────
export async function enqueueMutation(mutation: Omit<QueuedMutation, 'id' | 'createdAt'>): Promise<void> {
const db = await getDb();
await db.add('mutation_queue', { ...mutation, createdAt: Date.now() });
}
export async function getMutationQueue(): Promise<QueuedMutation[]> {
const db = await getDb();
return db.getAll('mutation_queue');
}
export async function dequeueMutation(id: number): Promise<void> {
const db = await getDb();
await db.delete('mutation_queue', id);
}
export async function getMutationQueueLength(): Promise<number> {
const db = await getDb();
return db.count('mutation_queue');
}