All files / src/server/repositories/implementations ItemDispositionRepository.ts

100% Statements 15/15
100% Branches 2/2
100% Functions 10/10
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110              181x               38x                           38x             20x                 20x       31x                 31x       64x                 64x       7x       7x       14x                 12x           74x                      
import { eq, and } from "drizzle-orm";
import type { Database } from "@/lib/db";
import { itemDispositionsTable } from "@/lib/db/schema";
import type { ItemDisposition, Disposition } from "@/types";
import { generateId } from "@/lib/id";
 
export class ItemDispositionRepository {
  constructor(private db: Database) {}
 
  async upsert(data: {
    collectionId: string;
    curatorId: string;
    itemId: string;
    disposition: Disposition;
  }): Promise<ItemDisposition> {
    const [row] = await this.db
      .insert(itemDispositionsTable)
      .values({
        id: generateId("disp"),
        collectionId: data.collectionId,
        curatorId: data.curatorId,
        itemId: data.itemId,
        disposition: data.disposition,
      })
      .onConflictDoUpdate({
        target: [itemDispositionsTable.itemId, itemDispositionsTable.curatorId],
        set: { disposition: data.disposition, updatedAt: new Date() },
      })
      .returning();
    return this.map(row);
  }
 
  async findByCollectionAndCurator(
    collectionId: string,
    curatorId: string,
  ): Promise<ItemDisposition[]> {
    const rows = await this.db
      .select()
      .from(itemDispositionsTable)
      .where(
        and(
          eq(itemDispositionsTable.collectionId, collectionId),
          eq(itemDispositionsTable.curatorId, curatorId),
        ),
      );
    return rows.map((r) => this.map(r));
  }
 
  async findByItem(itemId: string, curatorId: string): Promise<ItemDisposition | null> {
    const [row] = await this.db
      .select()
      .from(itemDispositionsTable)
      .where(
        and(
          eq(itemDispositionsTable.itemId, itemId),
          eq(itemDispositionsTable.curatorId, curatorId),
        ),
      );
    return row ? this.map(row) : null;
  }
 
  async delete(itemId: string, curatorId: string): Promise<number> {
    const deleted = await this.db
      .delete(itemDispositionsTable)
      .where(
        and(
          eq(itemDispositionsTable.itemId, itemId),
          eq(itemDispositionsTable.curatorId, curatorId),
        ),
      )
      .returning({ id: itemDispositionsTable.id });
    return deleted.length;
  }
 
  async deleteByItem(itemId: string): Promise<number> {
    const deleted = await this.db
      .delete(itemDispositionsTable)
      .where(eq(itemDispositionsTable.itemId, itemId))
      .returning({ id: itemDispositionsTable.id });
    return deleted.length;
  }
 
  async deleteByCollection(collectionId: string): Promise<void> {
    await this.db
      .delete(itemDispositionsTable)
      .where(eq(itemDispositionsTable.collectionId, collectionId));
  }
 
  // Purge-only (account deletion): remove every disposition for the given
  // curator across ALL collections. Not in the interface — used by
  // AccountDeletionService to clear the curator's borrowed-collection slice.
  async deleteByCurator(curatorId: string): Promise<void> {
    await this.db
      .delete(itemDispositionsTable)
      .where(eq(itemDispositionsTable.curatorId, curatorId));
  }
 
  private map(row: typeof itemDispositionsTable.$inferSelect): ItemDisposition {
    return {
      id: row.id,
      collectionId: row.collectionId,
      curatorId: row.curatorId,
      itemId: row.itemId,
      disposition: row.disposition as Disposition,
      createdAt: row.createdAt,
      updatedAt: row.updatedAt,
    };
  }
}