mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-22 14:38:10 +02:00
feat: implement server-side function to save session snapshots, including input validation and database table creation fallback.
This commit is contained in:
1 parent
0bec6b953b
commit
7288b3da72
1 file changed
+37
-40
@@ -46,49 +46,46 @@ export async function saveSnapshot(raw: unknown) {
|
|||||||
|
|
||||||
return { success: true, snapshotId: created?.id };
|
return { success: true, snapshotId: created?.id };
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("Snapshot DB error:", err);
|
console.error("Initial snapshot save failed, attempting auto-repair...", err);
|
||||||
|
|
||||||
// Détection plus large (code 42P01 ou texte relation does not exist)
|
try {
|
||||||
const isTableMissing = err.code === '42P01' ||
|
// Tentative systématique de création de table (no-op si déjà là)
|
||||||
err.message?.toLowerCase().includes("relation") ||
|
await db.execute(sql`
|
||||||
err.message?.toLowerCase().includes("does not exist");
|
CREATE TABLE IF NOT EXISTS session_snapshots (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
code_fournisseur VARCHAR(20) NOT NULL,
|
||||||
|
nom_fournisseur VARCHAR(255),
|
||||||
|
magasin VARCHAR(20) NOT NULL,
|
||||||
|
changes JSONB NOT NULL,
|
||||||
|
summary_json JSONB,
|
||||||
|
label TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
if (isTableMissing) {
|
// Deuxième tentative d'insertion
|
||||||
console.log("Table missing detected, attempting auto-repair...");
|
const [retryCreated] = await db
|
||||||
try {
|
.insert(sessionSnapshots)
|
||||||
await db.execute(sql`
|
.values({
|
||||||
CREATE TABLE IF NOT EXISTS session_snapshots (
|
codeFournisseur,
|
||||||
id SERIAL PRIMARY KEY,
|
nomFournisseur: nomFournisseur ?? null,
|
||||||
code_fournisseur VARCHAR(20) NOT NULL,
|
magasin,
|
||||||
nom_fournisseur VARCHAR(255),
|
label: label ?? `Snapshot — ${new Date().toLocaleDateString("fr-FR")}`,
|
||||||
magasin VARCHAR(20) NOT NULL,
|
changes,
|
||||||
changes JSONB NOT NULL,
|
summaryJson: summary ?? null,
|
||||||
summary_json JSONB,
|
})
|
||||||
label TEXT,
|
.returning({ id: sessionSnapshots.id });
|
||||||
created_at TIMESTAMP DEFAULT NOW()
|
|
||||||
);
|
|
||||||
`);
|
|
||||||
|
|
||||||
// On ré-essaie l'insertion une seule fois
|
return { success: true, snapshotId: retryCreated?.id };
|
||||||
const [retryCreated] = await db
|
} catch (repairErr: any) {
|
||||||
.insert(sessionSnapshots)
|
console.error("Snapshot auto-repair/retry failed:", repairErr);
|
||||||
.values({
|
// On renvoie les deux erreurs pour comprendre si c'est la création ou l'insertion qui échoue
|
||||||
codeFournisseur,
|
const origMsg = (err.message || String(err)).split('\n')[0];
|
||||||
nomFournisseur: nomFournisseur ?? null,
|
const retryMsg = (repairErr.message || String(repairErr)).split('\n')[0];
|
||||||
magasin,
|
return {
|
||||||
label: label ?? `Snapshot — ${new Date().toLocaleDateString("fr-FR")}`,
|
success: false,
|
||||||
changes,
|
error: `Erreur initiale: ${origMsg} | Erreur après réparation: ${retryMsg}`
|
||||||
summaryJson: summary ?? null,
|
};
|
||||||
})
|
|
||||||
.returning({ id: sessionSnapshots.id });
|
|
||||||
|
|
||||||
return { success: true, snapshotId: retryCreated?.id };
|
|
||||||
} catch (repairErr: any) {
|
|
||||||
console.error("Repair or retry failed:", repairErr);
|
|
||||||
return { success: false, error: `Repair/Retry failed: ${repairErr.message}` };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: false, error: `DB Error: ${err.message || String(err)}` };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user