mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-18 12:46:32 +02:00
fix(qlik): recreate hypercube per batch
This commit is contained in:
1 parent
850852912f
commit
f005c08ad6
1 file changed
+58
-33
+58
-33
@@ -116,31 +116,6 @@ export async function fetchNetworkMetricsPlaywright(
|
|||||||
setTimeout(() => rej(new Error("ws timeout")), 30000);
|
setTimeout(() => rej(new Error("ws timeout")), 30000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sélectionne Date + Article Code puis pagine le cube. Renvoie le nb de lignes
|
|
||||||
// brutes lues (avant dédoublonnage côté Node).
|
|
||||||
const PAGE = 1400;
|
|
||||||
const fetchCubeForSelection = async (oh: number, sink: Array<Array<string | number>>): Promise<number> => {
|
|
||||||
const layout = await rpc("GetLayout", {}, oh);
|
|
||||||
const size = ((layout.qLayout as { qHyperCube: { qSize: { qcy: number } } }).qHyperCube).qSize.qcy;
|
|
||||||
let got = 0;
|
|
||||||
for (let top = 0; top < size; top += PAGE) {
|
|
||||||
const d = await rpc("GetHyperCubeData", { qPath: "/qHyperCubeDef", qPages: [{ qTop: top, qLeft: 0, qWidth: 6, qHeight: PAGE }] }, oh);
|
|
||||||
const matrix = (d.qDataPages as Array<{ qMatrix?: Array<Array<{ qText?: string; qNum?: number }>> }>)?.[0]?.qMatrix ?? [];
|
|
||||||
if (!matrix.length) break;
|
|
||||||
for (const r of matrix) sink.push([
|
|
||||||
String(r[0]?.qText ?? ""),
|
|
||||||
Number(r[1]?.qNum) || 0,
|
|
||||||
Number(r[2]?.qNum) || 0,
|
|
||||||
Number(r[3]?.qNum) || 0,
|
|
||||||
Number(r[4]?.qNum) || 0,
|
|
||||||
Number(r[5]?.qNum) || 0,
|
|
||||||
]);
|
|
||||||
got += matrix.length;
|
|
||||||
if (matrix.length < PAGE) break;
|
|
||||||
}
|
|
||||||
return got;
|
|
||||||
};
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
await ready;
|
await ready;
|
||||||
@@ -170,15 +145,65 @@ export async function fetchNetworkMetricsPlaywright(
|
|||||||
const rCamag = pickMeasure("CA par Magasin N", mcamag);
|
const rCamag = pickMeasure("CA par Magasin N", mcamag);
|
||||||
const rMarge = pickMeasure("Marge % N", mmarge);
|
const rMarge = pickMeasure("Marge % N", mmarge);
|
||||||
console.log("measures résolues par titre: " + JSON.stringify({ rCamag, rMarge }) + " (sur " + items.length + " mesures)");
|
console.log("measures résolues par titre: " + JSON.stringify({ rCamag, rMarge }) + " (sur " + items.length + " mesures)");
|
||||||
const obj = await rpc("CreateSessionObject", { qProp: { qInfo: { qType: "cf-net" }, qHyperCubeDef: {
|
// L'hypercube session object est désormais créé JETABLE dans fetchCubeForSelection
|
||||||
qDimensions: [{ qLibraryId: dim }],
|
// (un objet par lot) puis DestroySessionObject — corrige "Request aborted" (code 15)
|
||||||
qMeasures: [{ qLibraryId: mca }, { qLibraryId: mqte }, { qLibraryId: mnb }, { qLibraryId: rCamag }, { qLibraryId: rMarge }],
|
// causé par la réutilisation du même objet sur des centaines de recalculs.
|
||||||
qInitialDataFetch: [],
|
|
||||||
} } }, doc);
|
|
||||||
const oh = (obj.qReturn as { qHandle: number }).qHandle;
|
|
||||||
|
|
||||||
const out: Array<Array<string | number>> = [];
|
const out: Array<Array<string | number>> = [];
|
||||||
|
|
||||||
|
// Sélectionne Date + Article Code puis pagine le cube. Renvoie le nb de lignes
|
||||||
|
// brutes lues (avant dédoublonnage côté Node).
|
||||||
|
//
|
||||||
|
// IMPORTANT : crée un hypercube session object JETABLE par lot (Date + Article Code
|
||||||
|
// déjà sélectionnés) puis le détruit. Réutiliser le même objet sur des centaines de
|
||||||
|
// lots force Qlik à recalculer en boucle et finit par "Request aborted" (code 15).
|
||||||
|
const PAGE = 1400;
|
||||||
|
const createCubeForBatch = async (): Promise<{ handle: number; id: string }> => {
|
||||||
|
const obj = await rpc("CreateSessionObject", { qProp: { qInfo: { qType: "cf-net" }, qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qLibraryId: dim }],
|
||||||
|
qMeasures: [{ qLibraryId: mca }, { qLibraryId: mqte }, { qLibraryId: mnb }, { qLibraryId: rCamag }, { qLibraryId: rMarge }],
|
||||||
|
qInitialDataFetch: [],
|
||||||
|
} } }, doc);
|
||||||
|
const qReturn = obj.qReturn as { qHandle: number; qGenericId?: string; qId?: string };
|
||||||
|
return { handle: qReturn.qHandle, id: String(qReturn.qGenericId ?? qReturn.qId ?? "") };
|
||||||
|
};
|
||||||
|
const destroyCube = async (cube: { handle: number; id: string }) => {
|
||||||
|
if (!cube.id) return;
|
||||||
|
try {
|
||||||
|
await rpc("DestroySessionObject", { qId: cube.id }, doc);
|
||||||
|
} catch (e) {
|
||||||
|
// Non fatal : l'objet est de toute façon scopé à la session websocket.
|
||||||
|
console.log("[qlik-pw] DestroySessionObject ignoré: " + String((e as Error)?.message || e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const fetchCubeForSelection = async (sink: Array<Array<string | number>>): Promise<number> => {
|
||||||
|
const cube = await createCubeForBatch();
|
||||||
|
const oh = cube.handle;
|
||||||
|
try {
|
||||||
|
const layout = await rpc("GetLayout", {}, oh);
|
||||||
|
const size = ((layout.qLayout as { qHyperCube: { qSize: { qcy: number } } }).qHyperCube).qSize.qcy;
|
||||||
|
let got = 0;
|
||||||
|
for (let top = 0; top < size; top += PAGE) {
|
||||||
|
const d = await rpc("GetHyperCubeData", { qPath: "/qHyperCubeDef", qPages: [{ qTop: top, qLeft: 0, qWidth: 6, qHeight: PAGE }] }, oh);
|
||||||
|
const matrix = (d.qDataPages as Array<{ qMatrix?: Array<Array<{ qText?: string; qNum?: number }>> }>)?.[0]?.qMatrix ?? [];
|
||||||
|
if (!matrix.length) break;
|
||||||
|
for (const r of matrix) sink.push([
|
||||||
|
String(r[0]?.qText ?? ""),
|
||||||
|
Number(r[1]?.qNum) || 0,
|
||||||
|
Number(r[2]?.qNum) || 0,
|
||||||
|
Number(r[3]?.qNum) || 0,
|
||||||
|
Number(r[4]?.qNum) || 0,
|
||||||
|
Number(r[5]?.qNum) || 0,
|
||||||
|
]);
|
||||||
|
got += matrix.length;
|
||||||
|
if (matrix.length < PAGE) break;
|
||||||
|
}
|
||||||
|
return got;
|
||||||
|
} finally {
|
||||||
|
await destroyCube(cube);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (noDateMode) {
|
if (noDateMode) {
|
||||||
// Aucun filtre Date : extraction en un seul appel (tous les codes d'un coup).
|
// Aucun filtre Date : extraction en un seul appel (tous les codes d'un coup).
|
||||||
// On sélectionne uniquement Article Code ; Date reste libre.
|
// On sélectionne uniquement Article Code ; Date reste libre.
|
||||||
@@ -187,7 +212,7 @@ export async function fetchNetworkMetricsPlaywright(
|
|||||||
const sel = await rpc("SelectValues", { qFieldValues: codes.map((c) => ({ qText: c })), qToggleMode: false, qSoftLock: true }, fh);
|
const sel = await rpc("SelectValues", { qFieldValues: codes.map((c) => ({ qText: c })), qToggleMode: false, qSoftLock: true }, fh);
|
||||||
console.log("SelectValues Article Code → " + JSON.stringify(sel.qReturn));
|
console.log("SelectValues Article Code → " + JSON.stringify(sel.qReturn));
|
||||||
}
|
}
|
||||||
const got = await fetchCubeForSelection(oh, out);
|
const got = await fetchCubeForSelection(out);
|
||||||
console.log("extraction sans date — " + got + " ligne(s), cumul=" + out.length);
|
console.log("extraction sans date — " + got + " ligne(s), cumul=" + out.length);
|
||||||
} else {
|
} else {
|
||||||
// Itération par mois × lots de codes : pour chaque mois, SelectValues Date
|
// Itération par mois × lots de codes : pour chaque mois, SelectValues Date
|
||||||
@@ -229,7 +254,7 @@ export async function fetchNetworkMetricsPlaywright(
|
|||||||
}, fh);
|
}, fh);
|
||||||
console.log(batchPrefix + " — SelectValues Article Code → " + JSON.stringify(csel.qReturn));
|
console.log(batchPrefix + " — SelectValues Article Code → " + JSON.stringify(csel.qReturn));
|
||||||
}
|
}
|
||||||
const got = await fetchCubeForSelection(oh, out);
|
const got = await fetchCubeForSelection(out);
|
||||||
console.log(batchPrefix + " — " + got + " ligne(s), cumul=" + out.length);
|
console.log(batchPrefix + " — " + got + " ligne(s), cumul=" + out.length);
|
||||||
} catch (batchErr) {
|
} catch (batchErr) {
|
||||||
const msg = String((batchErr as Error)?.message || batchErr);
|
const msg = String((batchErr as Error)?.message || batchErr);
|
||||||
|
|||||||
Reference in new issue
Block a user