import { and, desc, eq } from 'drizzle-orm' import type { drizzle } from 'drizzle-orm/postgres-js' import { notes, type Note } from '@/entities/note/model/schema' import type { NoteInput } from '@/entities/note/model/input' /** The handle the shared `db()` returns (`@/shared/api/db/server`). */ export type NoteDb = ReturnType /** * Note persistence over one database handle. The handle is a parameter so a test * can run the same code against its own Postgres. * * Every write names its author in the `where`: a visitor can change only the * notes they wrote (tenancy, D16). */ export function noteRepository(db: NoteDb) { return { async create(input: NoteInput & { authorId: string }): Promise { const [row] = await db.insert(notes).values(input).returning() if (!row) throw new Error('the insert returned no row') return row }, async get(id: string): Promise { const [row] = await db.select().from(notes).where(eq(notes.id, id)).limit(1) return row }, async listByAuthor(authorId: string, limit = 50): Promise { return db .select() .from(notes) .where(eq(notes.authorId, authorId)) .orderBy(desc(notes.createdAt)) .limit(limit) }, /** The updated note, or `undefined` when `authorId` did not write it. */ async update(id: string, authorId: string, input: NoteInput): Promise { const [row] = await db .update(notes) .set({ ...input, updatedAt: new Date() }) .where(and(eq(notes.id, id), eq(notes.authorId, authorId))) .returning() return row }, /** `true` when the note existed and `authorId` wrote it. */ async remove(id: string, authorId: string): Promise { const rows = await db .delete(notes) .where(and(eq(notes.id, id), eq(notes.authorId, authorId))) .returning({ id: notes.id }) return rows.length > 0 }, } } export type NoteRepository = ReturnType