From ebd819bfa4c2ac9f81d299793ca2e071748d9ed9 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Fri, 3 Apr 2026 10:58:43 +0200 Subject: [PATCH] feat: implement PostgreSQL bulk data access client to replace per-article HTTP requests --- src/db/index.ts | 5 +++++ src/lib/pg-ff-client.ts | 28 +++++++++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/db/index.ts b/src/db/index.ts index 4ebe51b..c894abc 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -7,6 +7,11 @@ import path from "path"; let pool: Pool | null = null; let currentDb: NodePgDatabase | null = null; +export function getPool(): Pool { + getDb(); // ensure pool is initialized + return pool!; +} + function maskUrl(url: string | undefined) { if (!url) return "undefined"; return url.replace(/:([^@]+)@/, ":****@"); diff --git a/src/lib/pg-ff-client.ts b/src/lib/pg-ff-client.ts index d4f20dc..85b2c75 100644 --- a/src/lib/pg-ff-client.ts +++ b/src/lib/pg-ff-client.ts @@ -7,7 +7,7 @@ * Chaque fonction fait 1 seule requête filtrée par codefou — O(1) au lieu de O(N). */ -import { db } from "@/db"; +import { db, getPool } from "@/db"; import { sql, type SQL } from "drizzle-orm"; // Cache module-level pour éviter les requêtes information_schema répétées @@ -753,22 +753,20 @@ export interface StockBySite { export async function pgGetStockForCodeins(codeins: string[]): Promise> { if (codeins.length === 0) return new Map(); - // Drizzle expands JS arrays into individual $1,$2,... params regardless of syntax, - // hitting PostgreSQL's 1664-entry ROW expression limit. Use sql.raw() with an escaped - // literal array instead — codeins come from the DB so single-quote escaping is sufficient. - const arrayLiteral = codeins.map(c => `'${String(c).replace(/'/g, "''")}'`).join(","); - const result = await pgNoParallel(sql` - SELECT - a.codein, - cs.site, - cs.stockdispo::float AS stockdispo - FROM cube_stock cs - JOIN articles a ON a.no_id = cs.artnoid - WHERE a.codein = ANY(ARRAY[${sql.raw(arrayLiteral)}]) - `); + // Bypass Drizzle entirely — it always expands arrays into individual params, + // hitting PG's 1664-entry ROW expression limit. Use the raw pg Pool directly + // with a native $1::text[] binding (entire array = single parameter). + const res = await getPool().query<{ codein: string; site: string; stockdispo: number }>( + `SELECT a.codein, cs.site, cs.stockdispo::float AS stockdispo + FROM cube_stock cs + JOIN articles a ON a.no_id = cs.artnoid + WHERE a.codein = ANY($1::text[])`, + [codeins] + ); + const rows = res.rows; const map = new Map(); - for (const r of result.rows as Array<{ codein: string; site: string; stockdispo: number }>) { + for (const r of rows) { if (!map.has(r.codein)) map.set(r.codein, { stock292: 0, stock579: 0, stockTotal: 0 }); const entry = map.get(r.codein)!; if (r.site === "292") entry.stock292 += r.stockdispo;