From 313230ab165b69598ac8f912b958aa28f9daf0a4 Mon Sep 17 00:00:00 2001 From: 4gray Date: Fri, 1 May 2026 21:15:03 +0200 Subject: [PATCH] perf(database): hoist prepared statement out of favorites reorder loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inner loop in reorderGlobalFavorites() rebuilt the same update().set().where() AST per row — up to thousands of times for large favorite lists. Hoist a prepared statement using sql.placeholder() so Drizzle generates the SQL string once and SQLite caches the parsed plan. Co-Authored-By: Claude Opus 4.7 (1M context) Entire-Checkpoint: 3d6901072049 --- .../database/operations/favorites.operations.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/electron-backend/src/app/database/operations/favorites.operations.ts b/apps/electron-backend/src/app/database/operations/favorites.operations.ts index de9ba9c55..c6c96988b 100644 --- a/apps/electron-backend/src/app/database/operations/favorites.operations.ts +++ b/apps/electron-backend/src/app/database/operations/favorites.operations.ts @@ -168,15 +168,21 @@ export async function reorderGlobalFavorites( let current = 0; const total = updates.length; + const updateFavoritePosition = db + .update(schema.favorites) + .set({ position: sql.placeholder('position') }) + .where(eq(schema.favorites.contentId, sql.placeholder('contentId'))) + .prepare(); + for (const chunk of chunkValues(updates, DEFAULT_BATCH_SIZE)) { await checkpointOperation(control); - await db.transaction(async (tx) => { + await db.transaction(async () => { for (const { content_id, position } of chunk) { - await tx - .update(schema.favorites) - .set({ position }) - .where(eq(schema.favorites.contentId, content_id)); + await updateFavoritePosition.execute({ + position, + contentId: content_id, + }); } });