feat: CSV-Import/-Export für Gerichte/Allergene/Zusatzstoffe, RSS-Fix für mehrere Essenszeiten
CSV-Import/-Export (Gerichte, Allergene, Zusatzstoffe): neue Export-/ Import-Routen unter app/api/*/export und */import, hand-geschriebener CSV-Parser/-Serializer (lib/csv.ts, keine neue Abhängigkeit), Upsert über Kürzel (Allergene/Zusatzstoffe) bzw. exakten Namen (Gerichte, mit Ambiguitäts-Check bei Namensdopplung). UI-Buttons in DishManager und CodeListManager. RSS-Feed: <content:encoded> zusätzlich zu <description> ausgeben, da mehrere Feed-Reader description als kürzbare Vorschau behandeln und dadurch bei mehreren Essenszeiten pro Tag nur die erste zeigten. Version 1.7.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+45
-1
@@ -1,5 +1,5 @@
|
||||
import "server-only";
|
||||
import { query, queryOne } from "@/lib/db";
|
||||
import { query, queryOne, withTransaction } from "@/lib/db";
|
||||
import type { CodeItem } from "@/lib/types";
|
||||
|
||||
// "allergens"/"additives" sind identisch aufgebaute Tabellen (Kürzel +
|
||||
@@ -39,3 +39,47 @@ export async function updateCode(
|
||||
export async function deleteCode(table: CodeTable, code: string): Promise<void> {
|
||||
await query(`delete from ${table} where code = $1`, [code]);
|
||||
}
|
||||
|
||||
export interface CodeImportRow {
|
||||
code: string;
|
||||
name: string;
|
||||
name_en: string | null;
|
||||
name_pl: string | null;
|
||||
}
|
||||
|
||||
/** CSV-Import: legt neue Kürzel an, bestehende (gleicher Code) werden
|
||||
* aktualisiert – ein doppelter Code innerhalb derselben Datei
|
||||
* aktualisiert also einfach zweimal statt einen Fehler zu werfen. */
|
||||
export async function importCodes(
|
||||
table: CodeTable,
|
||||
rows: CodeImportRow[]
|
||||
): Promise<{ created: number; updated: number }> {
|
||||
return withTransaction(async (client) => {
|
||||
const existing = await client.query<{ code: string }>(`select code from ${table}`);
|
||||
const known = new Set(existing.rows.map((r) => r.code));
|
||||
const maxRow = await client.query<{ sort: number }>(
|
||||
`select coalesce(max(sort), 0) as sort from ${table}`
|
||||
);
|
||||
let nextSort = (maxRow.rows[0]?.sort ?? 0) + 1;
|
||||
let created = 0;
|
||||
let updated = 0;
|
||||
|
||||
for (const row of rows) {
|
||||
if (known.has(row.code)) {
|
||||
await client.query(
|
||||
`update ${table} set name = $1, name_en = $2, name_pl = $3 where code = $4`,
|
||||
[row.name, row.name_en, row.name_pl, row.code]
|
||||
);
|
||||
updated++;
|
||||
} else {
|
||||
await client.query(
|
||||
`insert into ${table} (code, name, name_en, name_pl, sort) values ($1, $2, $3, $4, $5)`,
|
||||
[row.code, row.name, row.name_en, row.name_pl, nextSort++]
|
||||
);
|
||||
known.add(row.code);
|
||||
created++;
|
||||
}
|
||||
}
|
||||
return { created, updated };
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user