import { and, eq } from "drizzle-orm" import type { Database } from "../db/index.ts" import { userSources } from "../db/schema.ts" import { SourceNotFoundError } from "./errors.ts" export function sources(db: Database, userId: string) { return { /** Returns all enabled sources for the user. */ async enabled() { return db .select() .from(userSources) .where(and(eq(userSources.userId, userId), eq(userSources.enabled, true))) }, /** Returns a specific source by ID, or undefined. */ async find(sourceId: string) { const rows = await db .select() .from(userSources) .where(and(eq(userSources.userId, userId), eq(userSources.sourceId, sourceId))) .limit(1) return rows[0] }, /** Enables a source for the user. Throws if the source row doesn't exist. */ async enableSource(sourceId: string) { const rows = await db .update(userSources) .set({ enabled: true, updatedAt: new Date() }) .where(and(eq(userSources.userId, userId), eq(userSources.sourceId, sourceId))) .returning({ id: userSources.id }) if (rows.length === 0) { throw new SourceNotFoundError(sourceId, userId) } }, /** Disables a source for the user. Throws if the source row doesn't exist. */ async disableSource(sourceId: string) { const rows = await db .update(userSources) .set({ enabled: false, updatedAt: new Date() }) .where(and(eq(userSources.userId, userId), eq(userSources.sourceId, sourceId))) .returning({ id: userSources.id }) if (rows.length === 0) { throw new SourceNotFoundError(sourceId, userId) } }, /** Creates or updates the config for a source. */ async upsertConfig(sourceId: string, config: Record) { await db .insert(userSources) .values({ userId, sourceId, config }) .onConflictDoUpdate({ target: [userSources.userId, userSources.sourceId], set: { config, updatedAt: new Date() }, }) }, /** Updates the encrypted credentials for a source. Throws if the source row doesn't exist. */ async updateCredentials(sourceId: string, credentials: Buffer) { const rows = await db .update(userSources) .set({ credentials, updatedAt: new Date() }) .where(and(eq(userSources.userId, userId), eq(userSources.sourceId, sourceId))) .returning({ id: userSources.id }) if (rows.length === 0) { throw new SourceNotFoundError(sourceId, userId) } }, } }