From 40c5abbbed35f7d52aa907f30e72761aa2634784 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Sun, 30 Aug 2026 04:42:38 +0000 Subject: [PATCH] fix(metadata): handle large Hardcover libraries Bind book IDs as a PostgreSQL array so import previews do not exceed the wire-protocol parameter limit for large libraries. Fixes #1196 --- .../modules/hardcover/hardcover.repository.test.ts | 12 ++++++++++++ server/src/modules/hardcover/hardcover.repository.ts | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/server/src/modules/hardcover/hardcover.repository.test.ts b/server/src/modules/hardcover/hardcover.repository.test.ts index c8080e6cc..136d2209d 100644 --- a/server/src/modules/hardcover/hardcover.repository.test.ts +++ b/server/src/modules/hardcover/hardcover.repository.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it, vi, beforeEach } from 'vitest'; import { Permission } from '@bookorbit/types'; +import { PgDialect } from 'drizzle-orm/pg-core'; import * as schema from '../../db/schema'; import { HardcoverRepository } from './hardcover.repository'; @@ -126,6 +127,17 @@ describe('HardcoverRepository', () => { expect(bookStateQuery.findMany).toHaveBeenCalledTimes(1); }); + it('findBookStatesByBookIds binds large ID lists as one PostgreSQL array parameter', async () => { + const { repo, bookStateQuery } = makeRepository(); + const bookIds = Array.from({ length: 65_535 }, (_, index) => index + 1); + + await repo.findBookStatesByBookIds(7, bookIds); + + const config = bookStateQuery.findMany.mock.calls[0]![0] as { where: Parameters[0] }; + const query = new PgDialect().sqlToQuery(config.where); + expect(query.params).toEqual([7, bookIds]); + }); + it('upsertBookState inserts or updates per-book state', async () => { const { repo, db, bookStateInsert, bookStateRow } = makeRepository(); db.insert.mockReset(); diff --git a/server/src/modules/hardcover/hardcover.repository.ts b/server/src/modules/hardcover/hardcover.repository.ts index aa3902897..7c0a14040 100644 --- a/server/src/modules/hardcover/hardcover.repository.ts +++ b/server/src/modules/hardcover/hardcover.repository.ts @@ -130,7 +130,7 @@ export class HardcoverRepository { async findBookStatesByBookIds(userId: number, bookIds: number[]): Promise { if (bookIds.length === 0) return []; return this.db.query.hardcoverBookState.findMany({ - where: and(eq(schema.hardcoverBookState.userId, userId), inArray(schema.hardcoverBookState.bookId, bookIds)), + where: and(eq(schema.hardcoverBookState.userId, userId), sql`${schema.hardcoverBookState.bookId} = any(${sql.param(bookIds)}::integer[])`), }); }