fix: unique index words.titel_en als partial index + robuster Upsert ohne ON CONFLICT

- Migration: partiell WHERE IS NOT NULL, dedup vorher, kein silent-catch
- Route: INSERT mit .catch(23505) → UPDATE statt ON CONFLICT (partial index inkompatibel)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 21:14:21 +02:00
parent 1d25f84f5d
commit 455969bdec
2 changed files with 30 additions and 9 deletions

View File

@@ -77,17 +77,26 @@ router.post('/', async (req, res, next) => {
// Auto: alle 3 Sprachen direkt mitgeliefert + kein expliziter Status → 'translated'
const allLangs = titel_de && titel_en && titel_sv;
const effectiveStatus = status || (allLangs ? 'translated' : 'requested');
const result = await query(
// Upsert: neu anlegen oder bei doppeltem titel_en nur conc_m aktualisieren
let result = await query(
`INSERT INTO words (titel_de, titel_en, titel_sv, difficulty_level, status, conc_m, requested_at)
VALUES ($1, $2, $3, $4, $5, $6, NOW())
ON CONFLICT (titel_en) DO UPDATE SET conc_m = EXCLUDED.conc_m
RETURNING *, (xmax = 0) AS is_insert`,
VALUES ($1, $2, $3, $4, $5, $6, NOW()) RETURNING *, true AS is_insert`,
[titel_de || null, titel_en || null, titel_sv || null,
difficulty_level || null, effectiveStatus, conc_m ?? null]
);
).catch(async err => {
if (err.code === '23505' && titel_en) {
// Duplikat auf titel_en → conc_m aktualisieren und bestehende Zeile zurückgeben
const upd = await query(
`UPDATE words SET conc_m = $1 WHERE titel_en = $2 RETURNING *, false AS is_insert`,
[conc_m ?? null, titel_en]
);
return upd;
}
throw err;
});
const row = result.rows[0];
const { is_insert: _, ...word } = row;
res.status(row.is_insert ? 201 : 200).json({ ...word, picture_ids: [], category_ids: [] });
const { is_insert, ...word } = row;
res.status(is_insert ? 201 : 200).json({ ...word, picture_ids: [], category_ids: [] });
} catch (err) { next(err); }
});