From 6e8abc5091c6c265a3e5462c19e93fa0003e88d6 Mon Sep 17 00:00:00 2001 From: sepehr Date: Mon, 27 Apr 2026 00:36:03 +0200 Subject: [PATCH] fix: case-sensitive label matching broken on PostgreSQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit syncLabels created Labels with original case (e.g. "Projet") but searched with .toLowerCase() (e.g. "projet"). On PostgreSQL (case- sensitive), findMany returned [] → labelRelations disconnected → orphan cleanup deleted ALL notebook labels. Fix: use Prisma mode:'insensitive' for findFirst and findMany, deduplicate case-insensitively while preserving original case. Co-Authored-By: Claude Opus 4.7 --- memento-note/app/actions/notes.ts | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/memento-note/app/actions/notes.ts b/memento-note/app/actions/notes.ts index bc0b45f..763f558 100644 --- a/memento-note/app/actions/notes.ts +++ b/memento-note/app/actions/notes.ts @@ -107,12 +107,22 @@ async function syncLabels(userId: string, noteLabels: string[] = [], notebookId? const nbScope = notebookId ?? null if (noteLabels.length > 0) { - const trimmedNames = [...new Set( - noteLabels.map(name => name?.trim()).filter((n): n is string => Boolean(n)) - )] + // Deduplicate case-insensitively, keep original case + const seen = new Set() + const trimmedNames = noteLabels + .map(name => name?.trim()) + .filter((n): n is string => Boolean(n)) + .filter(n => { + const key = n.toLowerCase() + if (seen.has(key)) return false + seen.add(key) + return true + }) + for (const name of trimmedNames) { + // Case-insensitive find on PostgreSQL const existing = await prisma.label.findFirst({ - where: { userId, name, notebookId: nbScope }, + where: { userId, name: { equals: name, mode: 'insensitive' }, notebookId: nbScope }, }) if (!existing) { await prisma.label.create({ @@ -120,14 +130,16 @@ async function syncLabels(userId: string, noteLabels: string[] = [], notebookId? }) } } + + if (trimmedNames.length === 0) return [] + // Search with original case (case-insensitive on PostgreSQL) + return prisma.label.findMany({ + where: { userId, notebookId: nbScope, name: { in: trimmedNames, mode: 'insensitive' } }, + select: { id: true, name: true }, + }) } - if (noteLabels.length === 0) return [] - const uniqueNames = [...new Set(noteLabels.map(n => n.trim().toLowerCase()).filter(Boolean))] - return prisma.label.findMany({ - where: { userId, notebookId: nbScope, name: { in: uniqueNames } }, - select: { id: true, name: true }, - }) + return [] } catch (error) { console.error('Fatal error in syncLabels:', error) return []