import { Injectable, NotFoundException } from "@nestjs/common"; import { eq, sql } from "drizzle-orm"; import { UpdateReaderPreferencesDto } from "@readabook/shared"; import { DatabaseService } from "../database/database.service.js"; import { books, readerPreferences } from "../database/schema.js"; @Injectable() export class ReaderPreferencesService { constructor(private readonly database: DatabaseService) {} find(userId: number, bookId: number) { const row = this.database.db .select({ mode: readerPreferences.mode, fit: readerPreferences.fit, updatedAt: readerPreferences.updatedAt }) .from(readerPreferences) .where(sql`${readerPreferences.userId} = ${userId} AND ${readerPreferences.bookId} = ${bookId}`) .get(); return row ?? { mode: "paged", fit: null }; } upsert(userId: number, bookId: number, input: UpdateReaderPreferencesDto) { const book = this.database.db.select({ id: books.id }).from(books).where(eq(books.id, bookId)).get(); if (!book) throw new NotFoundException("Book not found"); const current = this.find(userId, bookId); const now = this.database.now(); const mode = input.mode ?? current.mode; const fit = input.fit === undefined ? current.fit : input.fit; this.database.sqlite .prepare( ` INSERT INTO reader_preferences(user_id, book_id, mode, fit, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(user_id, book_id) DO UPDATE SET mode = excluded.mode, fit = excluded.fit, updated_at = excluded.updated_at ` ) .run(userId, bookId, mode, fit, now, now); return this.find(userId, bookId); } }