@milaboratories/pf-driver 1.8.3 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/csv_writer.cjs +7 -5
- package/dist/csv_writer.cjs.map +1 -1
- package/dist/csv_writer.js +7 -5
- package/dist/csv_writer.js.map +1 -1
- package/dist/driver_decl.d.ts +3 -2
- package/dist/driver_decl.d.ts.map +1 -1
- package/dist/driver_impl.cjs +12 -3
- package/dist/driver_impl.cjs.map +1 -1
- package/dist/driver_impl.d.ts.map +1 -1
- package/dist/driver_impl.js +13 -4
- package/dist/driver_impl.js.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/csv_writer.test.ts +20 -0
- package/src/csv_writer.ts +25 -5
- package/src/driver_decl.ts +3 -2
- package/src/driver_double.test.ts +111 -1
- package/src/driver_impl.ts +21 -7
package/dist/csv_writer.cjs
CHANGED
|
@@ -3,16 +3,18 @@ let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
|
3
3
|
//#region src/csv_writer.ts
|
|
4
4
|
/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */
|
|
5
5
|
function formatHeader(specs, separator) {
|
|
6
|
-
return specs.map((spec) => escapeField(
|
|
6
|
+
return specs.map((spec) => escapeField(getNativeColumnLabel(spec), separator)).join(separator) + "\r\n";
|
|
7
7
|
}
|
|
8
8
|
/** Format a single data row from parallel vectors. Line ending is CRLF. */
|
|
9
9
|
function formatRow(vectors, rowIndex, separator) {
|
|
10
10
|
return vectors.map((vector) => escapeField(serializeValue(vector, rowIndex), separator)).join(separator) + "\r\n";
|
|
11
11
|
}
|
|
12
12
|
async function* streamPTableRows(options) {
|
|
13
|
-
const { pTable, columnIndices, range, chunkSize, separator, signal, specs
|
|
13
|
+
const { pTable, columnIndices, headerNames, range, chunkSize, separator, signal, specs } = options;
|
|
14
|
+
const { includeHeader, bom } = options;
|
|
15
|
+
if (headerNames !== void 0 && headerNames.length !== columnIndices.length) throw new Error(`headerNames length (${headerNames.length}) must match columnIndices length (${columnIndices.length})`);
|
|
14
16
|
if (bom) yield "";
|
|
15
|
-
if (includeHeader) yield formatHeader(columnIndices.map((index) => specs[index]), separator);
|
|
17
|
+
if (includeHeader) yield headerNames !== void 0 ? headerNames.map((name) => escapeField(name, separator)).join(separator) + "\r\n" : formatHeader(columnIndices.map((index) => specs[index]), separator);
|
|
16
18
|
if ((0, _milaboratories_helpers.isNil)(range)) return;
|
|
17
19
|
const end = range.offset + range.length;
|
|
18
20
|
for (let from = range.offset; from < end; from += chunkSize) {
|
|
@@ -32,7 +34,7 @@ async function* streamPTableRows(options) {
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
/** Extract a human-readable label from a PTableColumnSpec. */
|
|
35
|
-
function
|
|
37
|
+
function getNativeColumnLabel(spec) {
|
|
36
38
|
const annotation = (0, _milaboratories_pl_model_common.readAnnotation)(spec.spec, _milaboratories_pl_model_common.Annotation.Label);
|
|
37
39
|
return (0, _milaboratories_helpers.isNil)(annotation) ? spec.spec.name : annotation.trim();
|
|
38
40
|
}
|
|
@@ -73,9 +75,9 @@ function serializeValue(vector, rowIndex) {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
//#endregion
|
|
76
|
-
exports.columnLabel = columnLabel;
|
|
77
78
|
exports.formatHeader = formatHeader;
|
|
78
79
|
exports.formatRow = formatRow;
|
|
80
|
+
exports.getNativeColumnLabel = getNativeColumnLabel;
|
|
79
81
|
exports.streamPTableRows = streamPTableRows;
|
|
80
82
|
|
|
81
83
|
//# sourceMappingURL=csv_writer.cjs.map
|
package/dist/csv_writer.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv_writer.cjs","names":["Annotation","ValueType"],"sources":["../src/csv_writer.ts"],"sourcesContent":["import {\n Annotation,\n isValueNA,\n readAnnotation,\n ValueType,\n type PTableColumnSpec,\n type PTableVector,\n type TableRange,\n} from \"@milaboratories/pl-model-common\";\nimport { isNil } from \"@milaboratories/helpers\";\n\n/** Minimal subset of PTable required by streamPTableRows. */\nexport interface PTableDataSource {\n getData(\n columnIndices: number[],\n options?: { range?: TableRange; signal?: AbortSignal },\n ): Promise<PTableVector[]>;\n}\n\n// ── Public API (high-level → low-level) ──────────────────────────────\n\n/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */\nexport function formatHeader(specs: PTableColumnSpec[], separator: string): string {\n return specs.map((spec) => escapeField(
|
|
1
|
+
{"version":3,"file":"csv_writer.cjs","names":["Annotation","ValueType"],"sources":["../src/csv_writer.ts"],"sourcesContent":["import {\n Annotation,\n isValueNA,\n readAnnotation,\n ValueType,\n type PTableColumnSpec,\n type PTableVector,\n type TableRange,\n} from \"@milaboratories/pl-model-common\";\nimport { isNil } from \"@milaboratories/helpers\";\n\n/** Minimal subset of PTable required by streamPTableRows. */\nexport interface PTableDataSource {\n getData(\n columnIndices: number[],\n options?: { range?: TableRange; signal?: AbortSignal },\n ): Promise<PTableVector[]>;\n}\n\n// ── Public API (high-level → low-level) ──────────────────────────────\n\n/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */\nexport function formatHeader(specs: PTableColumnSpec[], separator: string): string {\n return (\n specs.map((spec) => escapeField(getNativeColumnLabel(spec), separator)).join(separator) + \"\\r\\n\"\n );\n}\n\n/** Format a single data row from parallel vectors. Line ending is CRLF. */\nexport function formatRow(vectors: PTableVector[], rowIndex: number, separator: string): string {\n return (\n vectors\n .map((vector) => escapeField(serializeValue(vector, rowIndex), separator))\n .join(separator) + \"\\r\\n\"\n );\n}\n\n/**\n * Async generator that streams CSV/TSV content chunk by chunk.\n *\n * The caller is responsible for providing a concrete `range` (already clipped\n * to the table shape). When `range` is undefined the generator does nothing\n * beyond emitting an optional BOM and header.\n */\nexport interface StreamPTableRowsOptions {\n pTable: PTableDataSource;\n specs: PTableColumnSpec[];\n columnIndices: number[];\n /**\n * Header names aligned 1:1 with `columnIndices`. When provided they are\n * written verbatim, letting callers supply disambiguated labels the spec's\n * intrinsic `pl7.app/label` may not carry. When omitted the header is derived\n * from `specs` via {@link getNativeColumnLabel}.\n */\n headerNames?: string[];\n range?: TableRange;\n chunkSize: number;\n separator: string;\n includeHeader: boolean;\n bom: boolean;\n signal?: AbortSignal;\n}\nexport async function* streamPTableRows(options: StreamPTableRowsOptions): AsyncIterable<string> {\n const { pTable, columnIndices, headerNames, range, chunkSize, separator, signal, specs } =\n options;\n const { includeHeader, bom } = options;\n\n if (headerNames !== undefined && headerNames.length !== columnIndices.length) {\n throw new Error(\n `headerNames length (${headerNames.length}) must match columnIndices length (${columnIndices.length})`,\n );\n }\n\n if (bom) {\n yield \"\\uFEFF\";\n }\n\n if (includeHeader) {\n yield headerNames !== undefined\n ? headerNames.map((name) => escapeField(name, separator)).join(separator) + \"\\r\\n\"\n : formatHeader(\n columnIndices.map((index) => specs[index]),\n separator,\n );\n }\n\n if (isNil(range)) {\n return;\n }\n\n const end = range.offset + range.length;\n\n for (let from = range.offset; from < end; from += chunkSize) {\n signal?.throwIfAborted();\n\n const length = Math.min(chunkSize, end - from);\n const subRange: TableRange = { offset: from, length };\n\n const vectors = await pTable.getData(columnIndices, { range: subRange, signal });\n\n const rows: string[] = [];\n for (let rowIndex = 0; rowIndex < length; rowIndex++) {\n rows.push(formatRow(vectors, rowIndex, separator));\n }\n yield rows.join(\"\");\n }\n}\n\n// ── Helpers (low-level) ──────────────────────────────────────────────\n\n/** Extract a human-readable label from a PTableColumnSpec. */\nexport function getNativeColumnLabel(spec: PTableColumnSpec): string {\n const annotation = readAnnotation(spec.spec, Annotation.Label);\n return isNil(annotation) ? spec.spec.name : annotation.trim();\n}\n\n/**\n * RFC 4180 field escaping.\n * Quote if the field contains the separator, a double-quote, CR, or LF.\n * Embedded `\"` are doubled.\n */\nfunction escapeField(value: string, separator: string): string {\n return needsQuoting(value, separator) ? '\"' + value.replace(/\"/g, '\"\"') + '\"' : value;\n}\n\n/** Returns true when the value must be wrapped in double-quotes. */\nfunction needsQuoting(value: string, separator: string): boolean {\n return (\n value.includes(separator) || value.includes('\"') || value.includes(\"\\r\") || value.includes(\"\\n\")\n );\n}\n\n/**\n * Serialize one cell value from a typed vector to its string representation.\n *\n * - `null` / `undefined` -> `\"\"`\n * - `bigint` -> `String(x)`\n * - `NaN` / `+Inf` / `-Inf` -> `\"\"`\n */\nfunction serializeValue(vector: PTableVector, rowIndex: number): string {\n const rawValue = vector.data[rowIndex];\n\n if (isNil(rawValue)) {\n return \"\";\n }\n\n if (isValueNA(vector, rowIndex)) {\n return \"\";\n }\n\n switch (vector.type) {\n case ValueType.Long: {\n // BigInt64Array element — may be stored as bigint\n return String(rawValue);\n }\n case ValueType.Float:\n case ValueType.Double: {\n const numeric = rawValue as number;\n return Number.isNaN(numeric) || !Number.isFinite(numeric) ? \"\" : String(numeric);\n }\n case ValueType.Int: {\n return String(rawValue);\n }\n case ValueType.String: {\n return rawValue as string;\n }\n case ValueType.Bytes: {\n return \"\";\n }\n default: {\n return String(rawValue);\n }\n }\n}\n"],"mappings":";;;;AAsBA,SAAgB,aAAa,OAA2B,WAA2B;CACjF,OACE,MAAM,KAAK,SAAS,YAAY,qBAAqB,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI;AAE9F;;AAGA,SAAgB,UAAU,SAAyB,UAAkB,WAA2B;CAC9F,OACE,QACG,KAAK,WAAW,YAAY,eAAe,QAAQ,QAAQ,GAAG,SAAS,CAAC,CAAC,CACzE,KAAK,SAAS,IAAI;AAEzB;AA2BA,gBAAuB,iBAAiB,SAAyD;CAC/F,MAAM,EAAE,QAAQ,eAAe,aAAa,OAAO,WAAW,WAAW,QAAQ,UAC/E;CACF,MAAM,EAAE,eAAe,QAAQ;CAE/B,IAAI,gBAAgB,KAAA,KAAa,YAAY,WAAW,cAAc,QACpE,MAAM,IAAI,MACR,uBAAuB,YAAY,OAAO,qCAAqC,cAAc,OAAO,EACtG;CAGF,IAAI,KACF,MAAM;CAGR,IAAI,eACF,MAAM,gBAAgB,KAAA,IAClB,YAAY,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,SAC1E,aACE,cAAc,KAAK,UAAU,MAAM,MAAM,GACzC,SACF;CAGN,KAAA,GAAA,wBAAA,MAAA,CAAU,KAAK,GACb;CAGF,MAAM,MAAM,MAAM,SAAS,MAAM;CAEjC,KAAK,IAAI,OAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW;EAC3D,QAAQ,eAAe;EAEvB,MAAM,SAAS,KAAK,IAAI,WAAW,MAAM,IAAI;EAC7C,MAAM,WAAuB;GAAE,QAAQ;GAAM;EAAO;EAEpD,MAAM,UAAU,MAAM,OAAO,QAAQ,eAAe;GAAE,OAAO;GAAU;EAAO,CAAC;EAE/E,MAAM,OAAiB,CAAC;EACxB,KAAK,IAAI,WAAW,GAAG,WAAW,QAAQ,YACxC,KAAK,KAAK,UAAU,SAAS,UAAU,SAAS,CAAC;EAEnD,MAAM,KAAK,KAAK,EAAE;CACpB;AACF;;AAKA,SAAgB,qBAAqB,MAAgC;CACnE,MAAM,cAAA,GAAA,gCAAA,eAAA,CAA4B,KAAK,MAAMA,gCAAAA,WAAW,KAAK;CAC7D,QAAA,GAAA,wBAAA,MAAA,CAAa,UAAU,IAAI,KAAK,KAAK,OAAO,WAAW,KAAK;AAC9D;;;;;;AAOA,SAAS,YAAY,OAAe,WAA2B;CAC7D,OAAO,aAAa,OAAO,SAAS,IAAI,OAAM,MAAM,QAAQ,MAAM,MAAI,IAAI,OAAM;AAClF;;AAGA,SAAS,aAAa,OAAe,WAA4B;CAC/D,OACE,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,IAAG,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI;AAEnG;;;;;;;;AASA,SAAS,eAAe,QAAsB,UAA0B;CACtE,MAAM,WAAW,OAAO,KAAK;CAE7B,KAAA,GAAA,wBAAA,MAAA,CAAU,QAAQ,GAChB,OAAO;CAGT,KAAA,GAAA,gCAAA,UAAA,CAAc,QAAQ,QAAQ,GAC5B,OAAO;CAGT,QAAQ,OAAO,MAAf;EACE,KAAKC,gCAAAA,UAAU,MAEb,OAAO,OAAO,QAAQ;EAExB,KAAKA,gCAAAA,UAAU;EACf,KAAKA,gCAAAA,UAAU,QAAQ;GACrB,MAAM,UAAU;GAChB,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC,OAAO,SAAS,OAAO,IAAI,KAAK,OAAO,OAAO;EACjF;EACA,KAAKA,gCAAAA,UAAU,KACb,OAAO,OAAO,QAAQ;EAExB,KAAKA,gCAAAA,UAAU,QACb,OAAO;EAET,KAAKA,gCAAAA,UAAU,OACb,OAAO;EAET,SACE,OAAO,OAAO,QAAQ;CAE1B;AACF"}
|
package/dist/csv_writer.js
CHANGED
|
@@ -3,16 +3,18 @@ import { isNil } from "@milaboratories/helpers";
|
|
|
3
3
|
//#region src/csv_writer.ts
|
|
4
4
|
/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */
|
|
5
5
|
function formatHeader(specs, separator) {
|
|
6
|
-
return specs.map((spec) => escapeField(
|
|
6
|
+
return specs.map((spec) => escapeField(getNativeColumnLabel(spec), separator)).join(separator) + "\r\n";
|
|
7
7
|
}
|
|
8
8
|
/** Format a single data row from parallel vectors. Line ending is CRLF. */
|
|
9
9
|
function formatRow(vectors, rowIndex, separator) {
|
|
10
10
|
return vectors.map((vector) => escapeField(serializeValue(vector, rowIndex), separator)).join(separator) + "\r\n";
|
|
11
11
|
}
|
|
12
12
|
async function* streamPTableRows(options) {
|
|
13
|
-
const { pTable, columnIndices, range, chunkSize, separator, signal, specs
|
|
13
|
+
const { pTable, columnIndices, headerNames, range, chunkSize, separator, signal, specs } = options;
|
|
14
|
+
const { includeHeader, bom } = options;
|
|
15
|
+
if (headerNames !== void 0 && headerNames.length !== columnIndices.length) throw new Error(`headerNames length (${headerNames.length}) must match columnIndices length (${columnIndices.length})`);
|
|
14
16
|
if (bom) yield "";
|
|
15
|
-
if (includeHeader) yield formatHeader(columnIndices.map((index) => specs[index]), separator);
|
|
17
|
+
if (includeHeader) yield headerNames !== void 0 ? headerNames.map((name) => escapeField(name, separator)).join(separator) + "\r\n" : formatHeader(columnIndices.map((index) => specs[index]), separator);
|
|
16
18
|
if (isNil(range)) return;
|
|
17
19
|
const end = range.offset + range.length;
|
|
18
20
|
for (let from = range.offset; from < end; from += chunkSize) {
|
|
@@ -32,7 +34,7 @@ async function* streamPTableRows(options) {
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
/** Extract a human-readable label from a PTableColumnSpec. */
|
|
35
|
-
function
|
|
37
|
+
function getNativeColumnLabel(spec) {
|
|
36
38
|
const annotation = readAnnotation(spec.spec, Annotation.Label);
|
|
37
39
|
return isNil(annotation) ? spec.spec.name : annotation.trim();
|
|
38
40
|
}
|
|
@@ -73,6 +75,6 @@ function serializeValue(vector, rowIndex) {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
//#endregion
|
|
76
|
-
export {
|
|
78
|
+
export { formatHeader, formatRow, getNativeColumnLabel, streamPTableRows };
|
|
77
79
|
|
|
78
80
|
//# sourceMappingURL=csv_writer.js.map
|
package/dist/csv_writer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv_writer.js","names":[],"sources":["../src/csv_writer.ts"],"sourcesContent":["import {\n Annotation,\n isValueNA,\n readAnnotation,\n ValueType,\n type PTableColumnSpec,\n type PTableVector,\n type TableRange,\n} from \"@milaboratories/pl-model-common\";\nimport { isNil } from \"@milaboratories/helpers\";\n\n/** Minimal subset of PTable required by streamPTableRows. */\nexport interface PTableDataSource {\n getData(\n columnIndices: number[],\n options?: { range?: TableRange; signal?: AbortSignal },\n ): Promise<PTableVector[]>;\n}\n\n// ── Public API (high-level → low-level) ──────────────────────────────\n\n/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */\nexport function formatHeader(specs: PTableColumnSpec[], separator: string): string {\n return specs.map((spec) => escapeField(
|
|
1
|
+
{"version":3,"file":"csv_writer.js","names":[],"sources":["../src/csv_writer.ts"],"sourcesContent":["import {\n Annotation,\n isValueNA,\n readAnnotation,\n ValueType,\n type PTableColumnSpec,\n type PTableVector,\n type TableRange,\n} from \"@milaboratories/pl-model-common\";\nimport { isNil } from \"@milaboratories/helpers\";\n\n/** Minimal subset of PTable required by streamPTableRows. */\nexport interface PTableDataSource {\n getData(\n columnIndices: number[],\n options?: { range?: TableRange; signal?: AbortSignal },\n ): Promise<PTableVector[]>;\n}\n\n// ── Public API (high-level → low-level) ──────────────────────────────\n\n/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */\nexport function formatHeader(specs: PTableColumnSpec[], separator: string): string {\n return (\n specs.map((spec) => escapeField(getNativeColumnLabel(spec), separator)).join(separator) + \"\\r\\n\"\n );\n}\n\n/** Format a single data row from parallel vectors. Line ending is CRLF. */\nexport function formatRow(vectors: PTableVector[], rowIndex: number, separator: string): string {\n return (\n vectors\n .map((vector) => escapeField(serializeValue(vector, rowIndex), separator))\n .join(separator) + \"\\r\\n\"\n );\n}\n\n/**\n * Async generator that streams CSV/TSV content chunk by chunk.\n *\n * The caller is responsible for providing a concrete `range` (already clipped\n * to the table shape). When `range` is undefined the generator does nothing\n * beyond emitting an optional BOM and header.\n */\nexport interface StreamPTableRowsOptions {\n pTable: PTableDataSource;\n specs: PTableColumnSpec[];\n columnIndices: number[];\n /**\n * Header names aligned 1:1 with `columnIndices`. When provided they are\n * written verbatim, letting callers supply disambiguated labels the spec's\n * intrinsic `pl7.app/label` may not carry. When omitted the header is derived\n * from `specs` via {@link getNativeColumnLabel}.\n */\n headerNames?: string[];\n range?: TableRange;\n chunkSize: number;\n separator: string;\n includeHeader: boolean;\n bom: boolean;\n signal?: AbortSignal;\n}\nexport async function* streamPTableRows(options: StreamPTableRowsOptions): AsyncIterable<string> {\n const { pTable, columnIndices, headerNames, range, chunkSize, separator, signal, specs } =\n options;\n const { includeHeader, bom } = options;\n\n if (headerNames !== undefined && headerNames.length !== columnIndices.length) {\n throw new Error(\n `headerNames length (${headerNames.length}) must match columnIndices length (${columnIndices.length})`,\n );\n }\n\n if (bom) {\n yield \"\\uFEFF\";\n }\n\n if (includeHeader) {\n yield headerNames !== undefined\n ? headerNames.map((name) => escapeField(name, separator)).join(separator) + \"\\r\\n\"\n : formatHeader(\n columnIndices.map((index) => specs[index]),\n separator,\n );\n }\n\n if (isNil(range)) {\n return;\n }\n\n const end = range.offset + range.length;\n\n for (let from = range.offset; from < end; from += chunkSize) {\n signal?.throwIfAborted();\n\n const length = Math.min(chunkSize, end - from);\n const subRange: TableRange = { offset: from, length };\n\n const vectors = await pTable.getData(columnIndices, { range: subRange, signal });\n\n const rows: string[] = [];\n for (let rowIndex = 0; rowIndex < length; rowIndex++) {\n rows.push(formatRow(vectors, rowIndex, separator));\n }\n yield rows.join(\"\");\n }\n}\n\n// ── Helpers (low-level) ──────────────────────────────────────────────\n\n/** Extract a human-readable label from a PTableColumnSpec. */\nexport function getNativeColumnLabel(spec: PTableColumnSpec): string {\n const annotation = readAnnotation(spec.spec, Annotation.Label);\n return isNil(annotation) ? spec.spec.name : annotation.trim();\n}\n\n/**\n * RFC 4180 field escaping.\n * Quote if the field contains the separator, a double-quote, CR, or LF.\n * Embedded `\"` are doubled.\n */\nfunction escapeField(value: string, separator: string): string {\n return needsQuoting(value, separator) ? '\"' + value.replace(/\"/g, '\"\"') + '\"' : value;\n}\n\n/** Returns true when the value must be wrapped in double-quotes. */\nfunction needsQuoting(value: string, separator: string): boolean {\n return (\n value.includes(separator) || value.includes('\"') || value.includes(\"\\r\") || value.includes(\"\\n\")\n );\n}\n\n/**\n * Serialize one cell value from a typed vector to its string representation.\n *\n * - `null` / `undefined` -> `\"\"`\n * - `bigint` -> `String(x)`\n * - `NaN` / `+Inf` / `-Inf` -> `\"\"`\n */\nfunction serializeValue(vector: PTableVector, rowIndex: number): string {\n const rawValue = vector.data[rowIndex];\n\n if (isNil(rawValue)) {\n return \"\";\n }\n\n if (isValueNA(vector, rowIndex)) {\n return \"\";\n }\n\n switch (vector.type) {\n case ValueType.Long: {\n // BigInt64Array element — may be stored as bigint\n return String(rawValue);\n }\n case ValueType.Float:\n case ValueType.Double: {\n const numeric = rawValue as number;\n return Number.isNaN(numeric) || !Number.isFinite(numeric) ? \"\" : String(numeric);\n }\n case ValueType.Int: {\n return String(rawValue);\n }\n case ValueType.String: {\n return rawValue as string;\n }\n case ValueType.Bytes: {\n return \"\";\n }\n default: {\n return String(rawValue);\n }\n }\n}\n"],"mappings":";;;;AAsBA,SAAgB,aAAa,OAA2B,WAA2B;CACjF,OACE,MAAM,KAAK,SAAS,YAAY,qBAAqB,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI;AAE9F;;AAGA,SAAgB,UAAU,SAAyB,UAAkB,WAA2B;CAC9F,OACE,QACG,KAAK,WAAW,YAAY,eAAe,QAAQ,QAAQ,GAAG,SAAS,CAAC,CAAC,CACzE,KAAK,SAAS,IAAI;AAEzB;AA2BA,gBAAuB,iBAAiB,SAAyD;CAC/F,MAAM,EAAE,QAAQ,eAAe,aAAa,OAAO,WAAW,WAAW,QAAQ,UAC/E;CACF,MAAM,EAAE,eAAe,QAAQ;CAE/B,IAAI,gBAAgB,KAAA,KAAa,YAAY,WAAW,cAAc,QACpE,MAAM,IAAI,MACR,uBAAuB,YAAY,OAAO,qCAAqC,cAAc,OAAO,EACtG;CAGF,IAAI,KACF,MAAM;CAGR,IAAI,eACF,MAAM,gBAAgB,KAAA,IAClB,YAAY,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,SAC1E,aACE,cAAc,KAAK,UAAU,MAAM,MAAM,GACzC,SACF;CAGN,IAAI,MAAM,KAAK,GACb;CAGF,MAAM,MAAM,MAAM,SAAS,MAAM;CAEjC,KAAK,IAAI,OAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW;EAC3D,QAAQ,eAAe;EAEvB,MAAM,SAAS,KAAK,IAAI,WAAW,MAAM,IAAI;EAC7C,MAAM,WAAuB;GAAE,QAAQ;GAAM;EAAO;EAEpD,MAAM,UAAU,MAAM,OAAO,QAAQ,eAAe;GAAE,OAAO;GAAU;EAAO,CAAC;EAE/E,MAAM,OAAiB,CAAC;EACxB,KAAK,IAAI,WAAW,GAAG,WAAW,QAAQ,YACxC,KAAK,KAAK,UAAU,SAAS,UAAU,SAAS,CAAC;EAEnD,MAAM,KAAK,KAAK,EAAE;CACpB;AACF;;AAKA,SAAgB,qBAAqB,MAAgC;CACnE,MAAM,aAAa,eAAe,KAAK,MAAM,WAAW,KAAK;CAC7D,OAAO,MAAM,UAAU,IAAI,KAAK,KAAK,OAAO,WAAW,KAAK;AAC9D;;;;;;AAOA,SAAS,YAAY,OAAe,WAA2B;CAC7D,OAAO,aAAa,OAAO,SAAS,IAAI,OAAM,MAAM,QAAQ,MAAM,MAAI,IAAI,OAAM;AAClF;;AAGA,SAAS,aAAa,OAAe,WAA4B;CAC/D,OACE,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,IAAG,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI;AAEnG;;;;;;;;AASA,SAAS,eAAe,QAAsB,UAA0B;CACtE,MAAM,WAAW,OAAO,KAAK;CAE7B,IAAI,MAAM,QAAQ,GAChB,OAAO;CAGT,IAAI,UAAU,QAAQ,QAAQ,GAC5B,OAAO;CAGT,QAAQ,OAAO,MAAf;EACE,KAAK,UAAU,MAEb,OAAO,OAAO,QAAQ;EAExB,KAAK,UAAU;EACf,KAAK,UAAU,QAAQ;GACrB,MAAM,UAAU;GAChB,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC,OAAO,SAAS,OAAO,IAAI,KAAK,OAAO,OAAO;EACjF;EACA,KAAK,UAAU,KACb,OAAO,OAAO,QAAQ;EAExB,KAAK,UAAU,QACb,OAAO;EAET,KAAK,UAAU,OACb,OAAO;EAET,SACE,OAAO,OAAO,QAAQ;CAE1B;AACF"}
|
package/dist/driver_decl.d.ts
CHANGED
|
@@ -51,8 +51,9 @@ interface AbstractInternalPFrameDriver<PColumnData> extends PFrameDriver, AsyncD
|
|
|
51
51
|
/**
|
|
52
52
|
* Export the table to a file, selecting the format from the extension of
|
|
53
53
|
* `options.path` (`csv`/`tsv`/`parquet`/`xlsx`). `options.columnIndices`
|
|
54
|
-
* selects the columns to export (output order);
|
|
55
|
-
*
|
|
54
|
+
* selects the columns to export (output order); optional
|
|
55
|
+
* `options.headerNames` (aligned 1:1) names them, with a missing or empty
|
|
56
|
+
* entry falling back to the field's label annotation (then the spec name).
|
|
56
57
|
*/
|
|
57
58
|
exportPTable(handle: PTableHandle, options: ExportPTableOptions, signal?: AbortSignal): Promise<void>;
|
|
58
59
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_decl.d.ts","names":[],"sources":["../src/driver_decl.ts"],"mappings":";;;;;;AAkCA;;;UAAiB,4BAAA,sBAAkD,YAAA,EAAc,eAAA;EAW1D;EATrB,OAAA,IAAW,OAAA;EAegB;;;;;;;EAN3B,SAAA,IAAa,OAAA,CAAQ,UAAA;EAee;;;;EATpC,eAAA,IAAmB,OAAA,CAAQ,cAAA,CAAe,YAAA;EAYF;EATxC,UAAA,IAAc,OAAA;EASM;EANpB,YAAA,CAAa,GAAA,EAAK,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAMN;EAHxD,YAAA,CAAa,GAAA,EAAK,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAQzB;EALrC,cAAA,CAAe,GAAA,EAAK,WAAA,CAAY,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAMzD;EAHT,kBAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,yBAAA,CAA0B,SAAA,GACnC,KAAA,EAAO,UAAA,cACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,0BAAA;EAAA;EAGX,eAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,mBAAA,EACT,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,oBAAA;EAHD;EAMV,QAAA,CAAS,MAAA,EAAQ,YAAA,EAAc,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,WAAA;EAJnD;;;;;;;;EAcX,OAAA,CACE,MAAA,EAAQ,YAAA,EACR,aAAA,YACA,KAAA,EAAO,UAAA,cACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,YAAA;EADA;EAIX,eAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,sBAAA,GACR,OAAA,CAAQ,qBAAA;EANR
|
|
1
|
+
{"version":3,"file":"driver_decl.d.ts","names":[],"sources":["../src/driver_decl.ts"],"mappings":";;;;;;AAkCA;;;UAAiB,4BAAA,sBAAkD,YAAA,EAAc,eAAA;EAW1D;EATrB,OAAA,IAAW,OAAA;EAegB;;;;;;;EAN3B,SAAA,IAAa,OAAA,CAAQ,UAAA;EAee;;;;EATpC,eAAA,IAAmB,OAAA,CAAQ,cAAA,CAAe,YAAA;EAYF;EATxC,UAAA,IAAc,OAAA;EASM;EANpB,YAAA,CAAa,GAAA,EAAK,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAMN;EAHxD,YAAA,CAAa,GAAA,EAAK,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAQzB;EALrC,cAAA,CAAe,GAAA,EAAK,WAAA,CAAY,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAMzD;EAHT,kBAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,yBAAA,CAA0B,SAAA,GACnC,KAAA,EAAO,UAAA,cACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,0BAAA;EAAA;EAGX,eAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,mBAAA,EACT,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,oBAAA;EAHD;EAMV,QAAA,CAAS,MAAA,EAAQ,YAAA,EAAc,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,WAAA;EAJnD;;;;;;;;EAcX,OAAA,CACE,MAAA,EAAQ,YAAA,EACR,aAAA,YACA,KAAA,EAAO,UAAA,cACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,YAAA;EADA;EAIX,eAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,sBAAA,GACR,OAAA,CAAQ,qBAAA;EANR;;;;;;;EAeH,YAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,mBAAA,EACT,MAAA,GAAS,WAAA,GACR,OAAA;AAAA"}
|
package/dist/driver_impl.cjs
CHANGED
|
@@ -153,6 +153,11 @@ var AbstractPFrameDriver = class {
|
|
|
153
153
|
const tableGuard = _usingCtx4.u(new _milaboratories_helpers.PoolEntryGuard(this.pTables.acquire(def)));
|
|
154
154
|
const { pTablePromise, disposeSignal } = tableGuard.resource;
|
|
155
155
|
const pTable = await pTablePromise;
|
|
156
|
+
const { columnIndices } = options;
|
|
157
|
+
const headerNames = columnIndices.map((index, i) => {
|
|
158
|
+
const name = options.headerNames?.[i];
|
|
159
|
+
return name !== void 0 && name !== "" ? name : require_csv_writer.getNativeColumnLabel(def.tableSpec[index]);
|
|
160
|
+
});
|
|
156
161
|
const combinedSignal = AbortSignal.any([options.signal, disposeSignal].filter((s) => !(0, _milaboratories_helpers.isNil)(s)));
|
|
157
162
|
const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {
|
|
158
163
|
const shape = await pTable.getShape({ signal: combinedSignal });
|
|
@@ -162,7 +167,8 @@ var AbstractPFrameDriver = class {
|
|
|
162
167
|
const iterable = require_csv_writer.streamPTableRows({
|
|
163
168
|
pTable,
|
|
164
169
|
specs,
|
|
165
|
-
columnIndices
|
|
170
|
+
columnIndices,
|
|
171
|
+
headerNames,
|
|
166
172
|
range: clippedRange,
|
|
167
173
|
chunkSize: options.chunkSize ?? 5e4,
|
|
168
174
|
separator,
|
|
@@ -187,7 +193,7 @@ var AbstractPFrameDriver = class {
|
|
|
187
193
|
const rowsWritten = clippedRange.length;
|
|
188
194
|
if (require_logging.logPFrames()) {
|
|
189
195
|
const durationMs = Math.round(performance.now() - startTime);
|
|
190
|
-
this.logger("info", `[WritePTableToFs] complete (handle = ${handle}, columns = ${
|
|
196
|
+
this.logger("info", `[WritePTableToFs] complete (handle = ${handle}, columns = ${columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`);
|
|
191
197
|
}
|
|
192
198
|
return {
|
|
193
199
|
result: {
|
|
@@ -217,7 +223,10 @@ var AbstractPFrameDriver = class {
|
|
|
217
223
|
const { pTablePromise, disposeSignal } = tableGuard.resource;
|
|
218
224
|
const pTable = await pTablePromise;
|
|
219
225
|
const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !(0, _milaboratories_helpers.isNil)(s)));
|
|
220
|
-
const headers = columnIndices.map((index) =>
|
|
226
|
+
const headers = columnIndices.map((index, i) => {
|
|
227
|
+
const name = options.headerNames?.[i];
|
|
228
|
+
return [index, name !== void 0 && name !== "" ? name : require_csv_writer.getNativeColumnLabel(def.tableSpec[index])];
|
|
229
|
+
});
|
|
221
230
|
const overallSize = await this.tableConcurrencyLimiter.run(async () => {
|
|
222
231
|
if (path.toLowerCase().endsWith(".xlsx")) {
|
|
223
232
|
const shape = await pTable.getShape({ signal: combinedSignal });
|
package/dist/driver_impl.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_impl.cjs","names":["PTableCachePerFrameOpsDefaults","PTableCachePlainOpsDefaults","PFrameFactory","ConcurrencyLimitingExecutor","PFramePool","PTableDefPool","PTablePool","PTableCachePerFrame","PTableCachePlain","ValueType","PoolEntryGuard","logPFrames","embedInlineColumnTypeSpecs","streamPTableRows","fs","Readable","zlib","columnLabel","XLSX_MAX_ROWS_PER_SHEET","PFrameDriverError","bigintReplacer"],"sources":["../src/driver_impl.ts"],"sourcesContent":["import {\n mapPObjectData,\n mapPTableDef,\n extractAllColumns,\n uniqueBy,\n canonicalizeJson,\n bigintReplacer,\n ValueType,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type FindColumnsRequest,\n type FindColumnsResponse,\n type PColumnIdAndSpec,\n type PColumnSpec,\n type PFrameHandle,\n type PObjectId,\n type PTableColumnSpec,\n type PTableHandle,\n type PTableShape,\n type PTableVector,\n type TableRange,\n type UniqueValuesRequest,\n type UniqueValuesResponse,\n type PColumn,\n type PFrameDef,\n type PTableDef,\n type PTableRecordSingleValueFilterV2,\n type PTableRecordFilter,\n type JsonSerializable,\n type PTableDefV2,\n mapSpecQueryColumns,\n collectSpecQueryColumns,\n sortSpecQuery,\n sortPTableDef,\n resolveAnnotationParents,\n PFrameDriverError,\n XLSX_MAX_ROWS_PER_SHEET,\n} from \"@milaboratories/pl-model-common\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n ConcurrencyLimitingExecutor,\n createPathAtomically,\n type MiLogger,\n} from \"@milaboratories/ts-helpers\";\nimport { isNil, PoolEntryGuard, type PoolEntry } from \"@milaboratories/helpers\";\nimport { PFrameFactory } from \"@milaboratories/pframes-rs-node\";\nimport { expandAxes, findTableColumn, rewriteLegacyFilters } from \"@milaboratories/pframes-rs-wasm\";\nimport { tmpdir } from \"node:os\";\nimport * as fs from \"node:fs\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport * as zlib from \"node:zlib\";\nimport { columnLabel, streamPTableRows } from \"./csv_writer\";\nimport type {\n AbstractInternalPFrameDriver,\n WritePTableToFsOptions,\n WritePTableToFsResult,\n ExportPTableOptions,\n} from \"./driver_decl\";\nimport { logPFrames } from \"./logging\";\nimport {\n PFramePool,\n type LocalBlobProvider as PoolLocalBlobProvider,\n type RemoteBlobProvider as PoolRemoteBlobProvider,\n} from \"./pframe_pool\";\nimport { PTableDefPool } from \"./ptable_def_pool\";\nimport { PTablePool } from \"./ptable_pool\";\nimport { embedInlineColumnTypeSpecs } from \"./ptable_shared\";\nimport {\n PTableCachePerFrame,\n PTableCachePerFrameOpsDefaults,\n type PTableCachePerFrameOps,\n} from \"./ptable_cache_per_frame\";\nimport {\n PTableCachePlain,\n PTableCachePlainOpsDefaults,\n type PTableCachePlainOps,\n} from \"./ptable_cache_plain\";\n\nexport interface LocalBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolLocalBlobProvider<TreeEntry>, AsyncDisposable {}\n\nexport interface RemoteBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolRemoteBlobProvider<TreeEntry>, AsyncDisposable {\n getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null>;\n resetCache(): Promise<void>;\n}\n\nexport type AbstractPFrameDriverOps = PTableCachePerFrameOps &\n PTableCachePlainOps & {\n /** Concurrency limits for `getUniqueValues` and `calculateTableData` requests */\n pFrameConcurrency: number;\n /** Concurrency limits for `getShape` and `getData` requests */\n pTableConcurrency: number;\n };\n\nexport const AbstractPFrameDriverOpsDefaults: AbstractPFrameDriverOps = {\n ...PTableCachePerFrameOpsDefaults,\n ...PTableCachePlainOpsDefaults,\n pFrameConcurrency: 1, // 1 join is executed in parallel and utilize all RAM and CPU cores\n pTableConcurrency: 1, // 1 joined table is read from disk at a time, which matches 1 table the user can view in the UI\n};\n\nexport type DataInfoResolver<PColumnData, TreeEntry extends JsonSerializable> = (\n spec: PColumnSpec,\n data: PColumnData,\n) => PFrameInternal.DataInfo<TreeEntry>;\n\nexport class AbstractPFrameDriver<\n PColumnData,\n TreeEntry extends JsonSerializable,\n> implements AbstractInternalPFrameDriver<PColumnData> {\n private readonly logger: PFrameInternal.Logger;\n\n private readonly localBlobProvider: LocalBlobProvider<TreeEntry>;\n private readonly remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n\n private readonly resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n\n private readonly pFrames: PFramePool<TreeEntry>;\n private readonly pTableDefs: PTableDefPool;\n private readonly pTables: PTablePool<TreeEntry>;\n\n private readonly pTableCachePerFrame: PTableCachePerFrame;\n private readonly pTableCachePlain: PTableCachePlain;\n\n private readonly frameConcurrencyLimiter: ConcurrencyLimitingExecutor;\n private readonly tableConcurrencyLimiter: ConcurrencyLimitingExecutor;\n\n public async pprofDump(): Promise<Uint8Array> {\n return await PFrameFactory.pprofDump();\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return await this.remoteBlobProvider.getCacheMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.remoteBlobProvider.resetCache();\n }\n\n public constructor({\n logger = () => {},\n localBlobProvider,\n remoteBlobProvider,\n spillPath = tmpdir(),\n options = AbstractPFrameDriverOpsDefaults,\n resolveDataInfo,\n }: {\n logger?: PFrameInternal.Logger;\n localBlobProvider: LocalBlobProvider<TreeEntry>;\n remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n spillPath?: string;\n options?: AbstractPFrameDriverOps;\n resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n }) {\n this.logger = logger;\n\n this.localBlobProvider = localBlobProvider;\n this.remoteBlobProvider = remoteBlobProvider;\n\n this.resolveDataInfo = resolveDataInfo;\n\n this.frameConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pFrameConcurrency);\n this.tableConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pTableConcurrency);\n\n this.pFrames = new PFramePool(\n this.localBlobProvider,\n this.remoteBlobProvider,\n this.logger,\n spillPath,\n );\n this.pTableDefs = new PTableDefPool(this.logger);\n this.pTables = new PTablePool(this.pFrames, this.pTableDefs, this.logger);\n\n this.pTableCachePerFrame = new PTableCachePerFrame(this.logger, options);\n this.pTableCachePlain = new PTableCachePlain(this.logger, options);\n }\n\n async dispose(): Promise<void> {\n void (await Promise.allSettled([\n this.pTables[Symbol.asyncDispose](),\n this.pTableDefs[Symbol.asyncDispose](),\n this.pFrames[Symbol.asyncDispose](),\n this.localBlobProvider[Symbol.asyncDispose](),\n this.remoteBlobProvider[Symbol.asyncDispose](),\n ]));\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n return await this.dispose();\n }\n\n //\n // Internal / Config API Methods\n //\n\n public createPFrame(def: PFrameDef<PColumn<PColumnData>>): PoolEntry<PFrameHandle> {\n const ValueTypes = new Set(Object.values(ValueType));\n const supportedColumns = def\n .filter((column) => ValueTypes.has(column.spec.valueType))\n .map((c) => ({ ...c, spec: resolveAnnotationParents(c.spec) }));\n const uniqueColumns = uniqueBy(supportedColumns, (column) => column.id);\n const columns = uniqueColumns.map((c) =>\n mapPObjectData(c, (d) => this.resolveDataInfo(c.spec, d)),\n );\n\n return this.pFrames.acquire(columns);\n }\n\n public createPTable(rawDef: PTableDef<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(extractAllColumns(rawDef.src), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const sortedDef = sortPTableDef(\n migrateTableFilter(\n mapPTableDef(rawDef, (c) => c.id),\n this.logger,\n ),\n );\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquireFromLegacy({\n pFrameHandle: pFrameGuard.key,\n def: sortedDef,\n pFrameSpec,\n }).entry,\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public createPTableV2(def: PTableDefV2<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(collectSpecQueryColumns(def.query), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n const sortedQuery = sortSpecQuery(mapSpecQueryColumns(def.query, { column: (c) => c.id }));\n const { tableSpec, dataQuery } = pFrameSpec.evaluateQuery(\n embedInlineColumnTypeSpecs(sortedQuery),\n );\n\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquire({\n pFrameHandle: pFrameGuard.key,\n tableSpec,\n dataQuery,\n }),\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public async writePTableToFs(\n handle: PTableHandle,\n options: WritePTableToFsOptions,\n ): Promise<WritePTableToFsResult> {\n this.logger(\n \"info\",\n `[WritePTableToFs] ENTER (handle = ${handle}, path = ${options.path}, format = ${options.format}, compression = ${options.compression ?? \"auto\"}, columns = ${options.columnIndices.length})`,\n );\n const startTime = performance.now();\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [options.signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // `combinedSignal` is passed twice on purpose: into the native calls for cooperative\n // cancellation, and into `run` so the concurrency slot is released on abort even if a\n // native call fails to unwind. Dropping the `run` signal reintroduces the queue wedge.\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({ signal: combinedSignal });\n const clippedRange = clipRange(options.range, shape);\n const specs = def.tableSpec;\n const separator = options.format === \"tsv\" ? \"\\t\" : \",\";\n\n const iterable = streamPTableRows({\n pTable,\n specs,\n columnIndices: options.columnIndices,\n range: clippedRange,\n chunkSize: options.chunkSize ?? 50_000,\n separator,\n includeHeader: options.includeHeader ?? true,\n bom: options.bom ?? true,\n signal: combinedSignal,\n });\n\n const miLogger: MiLogger = {\n info: (msg) => this.logger(\"info\", String(msg)),\n warn: (msg) => this.logger(\"warn\", String(msg)),\n error: (msg) => this.logger(\"error\", String(msg)),\n };\n\n let bytesWritten = 0;\n await createPathAtomically(miLogger, options.path, async (tempPath) => {\n const writeStream = fs.createWriteStream(tempPath, { flags: \"wx\" });\n const source = Readable.from(iterable, { objectMode: false });\n if (options.compression?.type === \"gzip\") {\n const gzip = zlib.createGzip({ level: options.compression.level ?? 6 });\n await pipeline(source, gzip, writeStream, { signal: combinedSignal });\n } else {\n await pipeline(source, writeStream, { signal: combinedSignal });\n }\n bytesWritten = writeStream.bytesWritten;\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n // rowsWritten equals the clipped range length — the generator streams the\n // entire effective range without early termination, so this is accurate.\n const rowsWritten = clippedRange.length;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[WritePTableToFs] complete (handle = ${handle}, columns = ${options.columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,\n );\n }\n\n return { result: { path: options.path, rowsWritten, bytesWritten }, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return result;\n }\n\n public async exportPTable(\n handle: PTableHandle,\n options: ExportPTableOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { path, columnIndices } = options;\n\n this.logger(\"info\", `[ExportPTable] ENTER (handle = ${handle}, path = ${path})`);\n const startTime = performance.now();\n\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n const headers: [number, string][] = columnIndices.map((index): [number, string] => [\n index,\n columnLabel(def.tableSpec[index]),\n ]);\n\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const overallSize = await this.tableConcurrencyLimiter.run(async () => {\n // Cap data rows per xlsx sheet below Excel's hard limit of 1,048,576.\n if (path.toLowerCase().endsWith(\".xlsx\")) {\n const shape = await pTable.getShape({ signal: combinedSignal });\n if (shape.rows > XLSX_MAX_ROWS_PER_SHEET) {\n const error = new PFrameDriverError(`exportPTable failed`);\n error.cause = new Error(\n `xlsx export rejected: ${shape.rows} rows exceed the per-sheet ` +\n `limit of ${XLSX_MAX_ROWS_PER_SHEET} rows`,\n );\n throw error;\n }\n }\n\n await pTable.export(path, { headers, signal: combinedSignal });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[ExportPTable] complete (handle = ${handle}, path = ${path}), ` +\n `duration = ${durationMs}ms`,\n );\n }\n\n return overallSize;\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n }\n\n //\n // PFrame instance methods\n //\n\n public async findColumns(\n handle: PFrameHandle,\n request: FindColumnsRequest,\n ): Promise<FindColumnsResponse> {\n const iRequest: PFrameInternal.FindColumnsRequest = {\n ...request,\n compatibleWith:\n request.compatibleWith.length !== 0\n ? [\n {\n axesSpec: [\n ...new Map(\n request.compatibleWith.map((item) => [canonicalizeJson(item), item] as const),\n ).values(),\n ],\n qualifications: [],\n },\n ]\n : [],\n };\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const response = pFrameSpec.findColumns(iRequest);\n return {\n hits: response.hits\n .filter(\n (h) =>\n // only exactly matching columns\n h.mappingVariants.length === 0 ||\n h.mappingVariants.some(\n (v) =>\n v.qualifications.forHit.length === 0 &&\n v.qualifications.forQueries.every((q) => q.length === 0),\n ),\n )\n .map((h) => h.hit),\n };\n }\n\n public async getColumnSpec(\n handle: PFrameHandle,\n columnId: PObjectId,\n ): Promise<PColumnSpec | null> {\n const { columnSpecs } = this.pFrames.getByKey(handle);\n return columnSpecs[columnId] ?? null;\n }\n\n public async listColumns(handle: PFrameHandle): Promise<PColumnIdAndSpec[]> {\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n return pFrameSpec.listColumns().map(({ columnId, spec }) => ({ columnId, spec }));\n }\n\n public async calculateTableData(\n handle: PFrameHandle,\n request: CalculateTableDataRequest<PObjectId>,\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<CalculateTableDataResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call calculateTableData, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const sortedDef = sortPTableDef(migrateTableFilter(request, this.logger));\n const { def, entry } = this.pTables.acquireFromLegacy({\n pFrameHandle: handle,\n def: sortedDef,\n pFrameSpec,\n });\n using tableGuard = new PoolEntryGuard(entry);\n const tableSpec = def.tableSpec;\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { data, overallSize } = await this.frameConcurrencyLimiter.run(async () => {\n // TODO: throw error when more then 200k rows is requested\n // after pf-plots migration to stream API\n\n const data = await pTable.getData([...tableSpec.keys()], {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePerFrame.cache(tableGuard.keep(), overallSize);\n return tableSpec.map((spec, i) => ({\n spec: spec,\n data: data[i],\n }));\n }\n\n public async getUniqueValues(\n handle: PFrameHandle,\n request: UniqueValuesRequest,\n signal?: AbortSignal,\n ): Promise<UniqueValuesResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call getUniqueValues, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameDataPromise, columnSpecs, disposeSignal } = this.pFrames.getByKey(handle);\n const pFrameData = await pFrameDataPromise;\n\n const columnSpec = columnSpecs[request.columnId];\n if (!columnSpec) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(`column ${request.columnId} is not registered in the PFrame`);\n throw error;\n }\n\n const axisIds = expandAxes(columnSpec.axesSpec);\n const tableSpec: PTableColumnSpec[] = [\n ...columnSpec.axesSpec.map(\n (axisSpec, i): PTableColumnSpec => ({\n type: \"axis\",\n id: axisIds[i],\n spec: axisSpec,\n }),\n ),\n { type: \"column\", id: request.columnId, spec: columnSpec },\n ];\n\n let axisIndex: number | undefined;\n if (request.axis !== undefined) {\n const index = findTableColumn(tableSpec, { type: \"axis\", id: request.axis });\n if (index < 0) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(\n `axis ${JSON.stringify(request.axis)} not found among axes of column ${request.columnId}`,\n );\n throw error;\n }\n axisIndex = index;\n }\n\n const resolvedRequest: PFrameInternal.UniqueValuesRequestV2 = {\n columnId: request.columnId,\n axisIndex,\n filters: rewriteLegacyFilters({\n tableSpec,\n filters: migrateFilters(request.filters, this.logger),\n }),\n limit: request.limit,\n };\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n return await this.frameConcurrencyLimiter.run(async () => {\n return await pFrameData.getUniqueValues(resolvedRequest, { signal: combinedSignal });\n }, combinedSignal);\n }\n\n //\n // PTable instance methods\n //\n\n public async getSpec(handle: PTableHandle): Promise<PTableColumnSpec[]> {\n const { def } = this.pTableDefs.getByKey(handle);\n return def.tableSpec;\n }\n\n public async getShape(handle: PTableHandle, signal?: AbortSignal): Promise<PTableShape> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { shape, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { shape, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return shape;\n }\n\n public async getData(\n handle: PTableHandle,\n columnIndices: number[],\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<PTableVector[]> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { data, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const data = await pTable.getData(columnIndices, {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return data;\n }\n}\n\n/** Clamp range to table shape. When range is undefined, returns full table range. */\nfunction clipRange(range: undefined | TableRange, shape: PTableShape): TableRange {\n if (isNil(range)) {\n return { offset: 0, length: shape.rows };\n }\n const clampedOffset = Math.min(range.offset, shape.rows);\n const clampedLength = Math.min(range.length, shape.rows - clampedOffset);\n return { offset: clampedOffset, length: clampedLength };\n}\n\nfunction migrateFilters(\n filters: PTableRecordFilter[],\n logger: PFrameInternal.Logger,\n): PTableRecordFilter[] {\n const filtersV1 = [];\n const filtersV2: PTableRecordSingleValueFilterV2[] = [];\n for (const filter of filters) {\n if ((filter.type as unknown) === \"bySingleColumn\") {\n filtersV1.push(filter);\n filtersV2.push({\n ...filter,\n type: \"bySingleColumnV2\",\n });\n } else {\n filtersV2.push(filter);\n }\n }\n if (filtersV1.length > 0) {\n const filtersV1Json = JSON.stringify(filtersV1);\n logger(\n \"warn\",\n `type overwritten from 'bySingleColumn' to 'bySingleColumnV2' for filters: ${filtersV1Json}`,\n );\n }\n return filtersV2;\n}\n\nfunction migrateTableFilter<T>(\n def: Omit<PTableDef<T>, \"partitionFilters\"> | PTableDef<T>,\n logger: PFrameInternal.Logger,\n): PTableDef<T> {\n if (!(\"partitionFilters\" in def)) {\n // For old blocks assume all axes filters to be partition filters\n return {\n ...def,\n partitionFilters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"axis\"),\n logger,\n ),\n filters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"column\"),\n logger,\n ),\n };\n }\n return {\n ...def,\n partitionFilters: migrateFilters(def.partitionFilters, logger),\n filters: migrateFilters(def.filters, logger),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"driver_impl.cjs","names":["PTableCachePerFrameOpsDefaults","PTableCachePlainOpsDefaults","PFrameFactory","ConcurrencyLimitingExecutor","PFramePool","PTableDefPool","PTablePool","PTableCachePerFrame","PTableCachePlain","ValueType","PoolEntryGuard","logPFrames","embedInlineColumnTypeSpecs","getNativeColumnLabel","streamPTableRows","fs","Readable","zlib","XLSX_MAX_ROWS_PER_SHEET","PFrameDriverError","bigintReplacer"],"sources":["../src/driver_impl.ts"],"sourcesContent":["import {\n mapPObjectData,\n mapPTableDef,\n extractAllColumns,\n uniqueBy,\n canonicalizeJson,\n bigintReplacer,\n ValueType,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type FindColumnsRequest,\n type FindColumnsResponse,\n type PColumnIdAndSpec,\n type PColumnSpec,\n type PFrameHandle,\n type PObjectId,\n type PTableColumnSpec,\n type PTableHandle,\n type PTableShape,\n type PTableVector,\n type TableRange,\n type UniqueValuesRequest,\n type UniqueValuesResponse,\n type PColumn,\n type PFrameDef,\n type PTableDef,\n type PTableRecordSingleValueFilterV2,\n type PTableRecordFilter,\n type JsonSerializable,\n type PTableDefV2,\n mapSpecQueryColumns,\n collectSpecQueryColumns,\n sortSpecQuery,\n sortPTableDef,\n resolveAnnotationParents,\n PFrameDriverError,\n XLSX_MAX_ROWS_PER_SHEET,\n} from \"@milaboratories/pl-model-common\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n ConcurrencyLimitingExecutor,\n createPathAtomically,\n type MiLogger,\n} from \"@milaboratories/ts-helpers\";\nimport { isNil, PoolEntryGuard, type PoolEntry } from \"@milaboratories/helpers\";\nimport { PFrameFactory } from \"@milaboratories/pframes-rs-node\";\nimport { expandAxes, findTableColumn, rewriteLegacyFilters } from \"@milaboratories/pframes-rs-wasm\";\nimport { tmpdir } from \"node:os\";\nimport * as fs from \"node:fs\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport * as zlib from \"node:zlib\";\nimport { getNativeColumnLabel, streamPTableRows } from \"./csv_writer\";\nimport type {\n AbstractInternalPFrameDriver,\n WritePTableToFsOptions,\n WritePTableToFsResult,\n ExportPTableOptions,\n} from \"./driver_decl\";\nimport { logPFrames } from \"./logging\";\nimport {\n PFramePool,\n type LocalBlobProvider as PoolLocalBlobProvider,\n type RemoteBlobProvider as PoolRemoteBlobProvider,\n} from \"./pframe_pool\";\nimport { PTableDefPool } from \"./ptable_def_pool\";\nimport { PTablePool } from \"./ptable_pool\";\nimport { embedInlineColumnTypeSpecs } from \"./ptable_shared\";\nimport {\n PTableCachePerFrame,\n PTableCachePerFrameOpsDefaults,\n type PTableCachePerFrameOps,\n} from \"./ptable_cache_per_frame\";\nimport {\n PTableCachePlain,\n PTableCachePlainOpsDefaults,\n type PTableCachePlainOps,\n} from \"./ptable_cache_plain\";\n\nexport interface LocalBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolLocalBlobProvider<TreeEntry>, AsyncDisposable {}\n\nexport interface RemoteBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolRemoteBlobProvider<TreeEntry>, AsyncDisposable {\n getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null>;\n resetCache(): Promise<void>;\n}\n\nexport type AbstractPFrameDriverOps = PTableCachePerFrameOps &\n PTableCachePlainOps & {\n /** Concurrency limits for `getUniqueValues` and `calculateTableData` requests */\n pFrameConcurrency: number;\n /** Concurrency limits for `getShape` and `getData` requests */\n pTableConcurrency: number;\n };\n\nexport const AbstractPFrameDriverOpsDefaults: AbstractPFrameDriverOps = {\n ...PTableCachePerFrameOpsDefaults,\n ...PTableCachePlainOpsDefaults,\n pFrameConcurrency: 1, // 1 join is executed in parallel and utilize all RAM and CPU cores\n pTableConcurrency: 1, // 1 joined table is read from disk at a time, which matches 1 table the user can view in the UI\n};\n\nexport type DataInfoResolver<PColumnData, TreeEntry extends JsonSerializable> = (\n spec: PColumnSpec,\n data: PColumnData,\n) => PFrameInternal.DataInfo<TreeEntry>;\n\nexport class AbstractPFrameDriver<\n PColumnData,\n TreeEntry extends JsonSerializable,\n> implements AbstractInternalPFrameDriver<PColumnData> {\n private readonly logger: PFrameInternal.Logger;\n\n private readonly localBlobProvider: LocalBlobProvider<TreeEntry>;\n private readonly remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n\n private readonly resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n\n private readonly pFrames: PFramePool<TreeEntry>;\n private readonly pTableDefs: PTableDefPool;\n private readonly pTables: PTablePool<TreeEntry>;\n\n private readonly pTableCachePerFrame: PTableCachePerFrame;\n private readonly pTableCachePlain: PTableCachePlain;\n\n private readonly frameConcurrencyLimiter: ConcurrencyLimitingExecutor;\n private readonly tableConcurrencyLimiter: ConcurrencyLimitingExecutor;\n\n public async pprofDump(): Promise<Uint8Array> {\n return await PFrameFactory.pprofDump();\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return await this.remoteBlobProvider.getCacheMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.remoteBlobProvider.resetCache();\n }\n\n public constructor({\n logger = () => {},\n localBlobProvider,\n remoteBlobProvider,\n spillPath = tmpdir(),\n options = AbstractPFrameDriverOpsDefaults,\n resolveDataInfo,\n }: {\n logger?: PFrameInternal.Logger;\n localBlobProvider: LocalBlobProvider<TreeEntry>;\n remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n spillPath?: string;\n options?: AbstractPFrameDriverOps;\n resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n }) {\n this.logger = logger;\n\n this.localBlobProvider = localBlobProvider;\n this.remoteBlobProvider = remoteBlobProvider;\n\n this.resolveDataInfo = resolveDataInfo;\n\n this.frameConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pFrameConcurrency);\n this.tableConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pTableConcurrency);\n\n this.pFrames = new PFramePool(\n this.localBlobProvider,\n this.remoteBlobProvider,\n this.logger,\n spillPath,\n );\n this.pTableDefs = new PTableDefPool(this.logger);\n this.pTables = new PTablePool(this.pFrames, this.pTableDefs, this.logger);\n\n this.pTableCachePerFrame = new PTableCachePerFrame(this.logger, options);\n this.pTableCachePlain = new PTableCachePlain(this.logger, options);\n }\n\n async dispose(): Promise<void> {\n void (await Promise.allSettled([\n this.pTables[Symbol.asyncDispose](),\n this.pTableDefs[Symbol.asyncDispose](),\n this.pFrames[Symbol.asyncDispose](),\n this.localBlobProvider[Symbol.asyncDispose](),\n this.remoteBlobProvider[Symbol.asyncDispose](),\n ]));\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n return await this.dispose();\n }\n\n //\n // Internal / Config API Methods\n //\n\n public createPFrame(def: PFrameDef<PColumn<PColumnData>>): PoolEntry<PFrameHandle> {\n const ValueTypes = new Set(Object.values(ValueType));\n const supportedColumns = def\n .filter((column) => ValueTypes.has(column.spec.valueType))\n .map((c) => ({ ...c, spec: resolveAnnotationParents(c.spec) }));\n const uniqueColumns = uniqueBy(supportedColumns, (column) => column.id);\n const columns = uniqueColumns.map((c) =>\n mapPObjectData(c, (d) => this.resolveDataInfo(c.spec, d)),\n );\n\n return this.pFrames.acquire(columns);\n }\n\n public createPTable(rawDef: PTableDef<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(extractAllColumns(rawDef.src), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const sortedDef = sortPTableDef(\n migrateTableFilter(\n mapPTableDef(rawDef, (c) => c.id),\n this.logger,\n ),\n );\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquireFromLegacy({\n pFrameHandle: pFrameGuard.key,\n def: sortedDef,\n pFrameSpec,\n }).entry,\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public createPTableV2(def: PTableDefV2<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(collectSpecQueryColumns(def.query), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n const sortedQuery = sortSpecQuery(mapSpecQueryColumns(def.query, { column: (c) => c.id }));\n const { tableSpec, dataQuery } = pFrameSpec.evaluateQuery(\n embedInlineColumnTypeSpecs(sortedQuery),\n );\n\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquire({\n pFrameHandle: pFrameGuard.key,\n tableSpec,\n dataQuery,\n }),\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public async writePTableToFs(\n handle: PTableHandle,\n options: WritePTableToFsOptions,\n ): Promise<WritePTableToFsResult> {\n this.logger(\n \"info\",\n `[WritePTableToFs] ENTER (handle = ${handle}, path = ${options.path}, format = ${options.format}, compression = ${options.compression ?? \"auto\"}, columns = ${options.columnIndices.length})`,\n );\n const startTime = performance.now();\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n // Caller-supplied header names win (they carry the disambiguated labels the\n // UI shows); a missing or empty name falls back to the spec-derived label.\n const { columnIndices } = options;\n const headerNames = columnIndices.map((index, i) => {\n const name = options.headerNames?.[i];\n return name !== undefined && name !== \"\" ? name : getNativeColumnLabel(def.tableSpec[index]);\n });\n\n const combinedSignal = AbortSignal.any(\n [options.signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // `combinedSignal` is passed twice on purpose: into the native calls for cooperative\n // cancellation, and into `run` so the concurrency slot is released on abort even if a\n // native call fails to unwind. Dropping the `run` signal reintroduces the queue wedge.\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({ signal: combinedSignal });\n const clippedRange = clipRange(options.range, shape);\n const specs = def.tableSpec;\n const separator = options.format === \"tsv\" ? \"\\t\" : \",\";\n\n const iterable = streamPTableRows({\n pTable,\n specs,\n columnIndices,\n headerNames,\n range: clippedRange,\n chunkSize: options.chunkSize ?? 50_000,\n separator,\n includeHeader: options.includeHeader ?? true,\n bom: options.bom ?? true,\n signal: combinedSignal,\n });\n\n const miLogger: MiLogger = {\n info: (msg) => this.logger(\"info\", String(msg)),\n warn: (msg) => this.logger(\"warn\", String(msg)),\n error: (msg) => this.logger(\"error\", String(msg)),\n };\n\n let bytesWritten = 0;\n await createPathAtomically(miLogger, options.path, async (tempPath) => {\n const writeStream = fs.createWriteStream(tempPath, { flags: \"wx\" });\n const source = Readable.from(iterable, { objectMode: false });\n if (options.compression?.type === \"gzip\") {\n const gzip = zlib.createGzip({ level: options.compression.level ?? 6 });\n await pipeline(source, gzip, writeStream, { signal: combinedSignal });\n } else {\n await pipeline(source, writeStream, { signal: combinedSignal });\n }\n bytesWritten = writeStream.bytesWritten;\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n // rowsWritten equals the clipped range length — the generator streams the\n // entire effective range without early termination, so this is accurate.\n const rowsWritten = clippedRange.length;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[WritePTableToFs] complete (handle = ${handle}, columns = ${columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,\n );\n }\n\n return { result: { path: options.path, rowsWritten, bytesWritten }, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return result;\n }\n\n public async exportPTable(\n handle: PTableHandle,\n options: ExportPTableOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { path, columnIndices } = options;\n\n this.logger(\"info\", `[ExportPTable] ENTER (handle = ${handle}, path = ${path})`);\n const startTime = performance.now();\n\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // Caller-supplied header names win (they carry the disambiguated labels the\n // UI shows); a missing or empty name falls back to the spec-derived label.\n const headers: [number, string][] = columnIndices.map((index, i): [number, string] => {\n const name = options.headerNames?.[i];\n return [\n index,\n name !== undefined && name !== \"\" ? name : getNativeColumnLabel(def.tableSpec[index]),\n ];\n });\n\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const overallSize = await this.tableConcurrencyLimiter.run(async () => {\n // Cap data rows per xlsx sheet below Excel's hard limit of 1,048,576.\n if (path.toLowerCase().endsWith(\".xlsx\")) {\n const shape = await pTable.getShape({ signal: combinedSignal });\n if (shape.rows > XLSX_MAX_ROWS_PER_SHEET) {\n const error = new PFrameDriverError(`exportPTable failed`);\n error.cause = new Error(\n `xlsx export rejected: ${shape.rows} rows exceed the per-sheet ` +\n `limit of ${XLSX_MAX_ROWS_PER_SHEET} rows`,\n );\n throw error;\n }\n }\n\n await pTable.export(path, { headers, signal: combinedSignal });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[ExportPTable] complete (handle = ${handle}, path = ${path}), ` +\n `duration = ${durationMs}ms`,\n );\n }\n\n return overallSize;\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n }\n\n //\n // PFrame instance methods\n //\n\n public async findColumns(\n handle: PFrameHandle,\n request: FindColumnsRequest,\n ): Promise<FindColumnsResponse> {\n const iRequest: PFrameInternal.FindColumnsRequest = {\n ...request,\n compatibleWith:\n request.compatibleWith.length !== 0\n ? [\n {\n axesSpec: [\n ...new Map(\n request.compatibleWith.map((item) => [canonicalizeJson(item), item] as const),\n ).values(),\n ],\n qualifications: [],\n },\n ]\n : [],\n };\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const response = pFrameSpec.findColumns(iRequest);\n return {\n hits: response.hits\n .filter(\n (h) =>\n // only exactly matching columns\n h.mappingVariants.length === 0 ||\n h.mappingVariants.some(\n (v) =>\n v.qualifications.forHit.length === 0 &&\n v.qualifications.forQueries.every((q) => q.length === 0),\n ),\n )\n .map((h) => h.hit),\n };\n }\n\n public async getColumnSpec(\n handle: PFrameHandle,\n columnId: PObjectId,\n ): Promise<PColumnSpec | null> {\n const { columnSpecs } = this.pFrames.getByKey(handle);\n return columnSpecs[columnId] ?? null;\n }\n\n public async listColumns(handle: PFrameHandle): Promise<PColumnIdAndSpec[]> {\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n return pFrameSpec.listColumns().map(({ columnId, spec }) => ({ columnId, spec }));\n }\n\n public async calculateTableData(\n handle: PFrameHandle,\n request: CalculateTableDataRequest<PObjectId>,\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<CalculateTableDataResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call calculateTableData, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const sortedDef = sortPTableDef(migrateTableFilter(request, this.logger));\n const { def, entry } = this.pTables.acquireFromLegacy({\n pFrameHandle: handle,\n def: sortedDef,\n pFrameSpec,\n });\n using tableGuard = new PoolEntryGuard(entry);\n const tableSpec = def.tableSpec;\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { data, overallSize } = await this.frameConcurrencyLimiter.run(async () => {\n // TODO: throw error when more then 200k rows is requested\n // after pf-plots migration to stream API\n\n const data = await pTable.getData([...tableSpec.keys()], {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePerFrame.cache(tableGuard.keep(), overallSize);\n return tableSpec.map((spec, i) => ({\n spec: spec,\n data: data[i],\n }));\n }\n\n public async getUniqueValues(\n handle: PFrameHandle,\n request: UniqueValuesRequest,\n signal?: AbortSignal,\n ): Promise<UniqueValuesResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call getUniqueValues, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameDataPromise, columnSpecs, disposeSignal } = this.pFrames.getByKey(handle);\n const pFrameData = await pFrameDataPromise;\n\n const columnSpec = columnSpecs[request.columnId];\n if (!columnSpec) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(`column ${request.columnId} is not registered in the PFrame`);\n throw error;\n }\n\n const axisIds = expandAxes(columnSpec.axesSpec);\n const tableSpec: PTableColumnSpec[] = [\n ...columnSpec.axesSpec.map(\n (axisSpec, i): PTableColumnSpec => ({\n type: \"axis\",\n id: axisIds[i],\n spec: axisSpec,\n }),\n ),\n { type: \"column\", id: request.columnId, spec: columnSpec },\n ];\n\n let axisIndex: number | undefined;\n if (request.axis !== undefined) {\n const index = findTableColumn(tableSpec, { type: \"axis\", id: request.axis });\n if (index < 0) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(\n `axis ${JSON.stringify(request.axis)} not found among axes of column ${request.columnId}`,\n );\n throw error;\n }\n axisIndex = index;\n }\n\n const resolvedRequest: PFrameInternal.UniqueValuesRequestV2 = {\n columnId: request.columnId,\n axisIndex,\n filters: rewriteLegacyFilters({\n tableSpec,\n filters: migrateFilters(request.filters, this.logger),\n }),\n limit: request.limit,\n };\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n return await this.frameConcurrencyLimiter.run(async () => {\n return await pFrameData.getUniqueValues(resolvedRequest, { signal: combinedSignal });\n }, combinedSignal);\n }\n\n //\n // PTable instance methods\n //\n\n public async getSpec(handle: PTableHandle): Promise<PTableColumnSpec[]> {\n const { def } = this.pTableDefs.getByKey(handle);\n return def.tableSpec;\n }\n\n public async getShape(handle: PTableHandle, signal?: AbortSignal): Promise<PTableShape> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { shape, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { shape, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return shape;\n }\n\n public async getData(\n handle: PTableHandle,\n columnIndices: number[],\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<PTableVector[]> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { data, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const data = await pTable.getData(columnIndices, {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return data;\n }\n}\n\n/** Clamp range to table shape. When range is undefined, returns full table range. */\nfunction clipRange(range: undefined | TableRange, shape: PTableShape): TableRange {\n if (isNil(range)) {\n return { offset: 0, length: shape.rows };\n }\n const clampedOffset = Math.min(range.offset, shape.rows);\n const clampedLength = Math.min(range.length, shape.rows - clampedOffset);\n return { offset: clampedOffset, length: clampedLength };\n}\n\nfunction migrateFilters(\n filters: PTableRecordFilter[],\n logger: PFrameInternal.Logger,\n): PTableRecordFilter[] {\n const filtersV1 = [];\n const filtersV2: PTableRecordSingleValueFilterV2[] = [];\n for (const filter of filters) {\n if ((filter.type as unknown) === \"bySingleColumn\") {\n filtersV1.push(filter);\n filtersV2.push({\n ...filter,\n type: \"bySingleColumnV2\",\n });\n } else {\n filtersV2.push(filter);\n }\n }\n if (filtersV1.length > 0) {\n const filtersV1Json = JSON.stringify(filtersV1);\n logger(\n \"warn\",\n `type overwritten from 'bySingleColumn' to 'bySingleColumnV2' for filters: ${filtersV1Json}`,\n );\n }\n return filtersV2;\n}\n\nfunction migrateTableFilter<T>(\n def: Omit<PTableDef<T>, \"partitionFilters\"> | PTableDef<T>,\n logger: PFrameInternal.Logger,\n): PTableDef<T> {\n if (!(\"partitionFilters\" in def)) {\n // For old blocks assume all axes filters to be partition filters\n return {\n ...def,\n partitionFilters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"axis\"),\n logger,\n ),\n filters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"column\"),\n logger,\n ),\n };\n }\n return {\n ...def,\n partitionFilters: migrateFilters(def.partitionFilters, logger),\n filters: migrateFilters(def.filters, logger),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_impl.d.ts","names":[],"sources":["../src/driver_impl.ts"],"mappings":";;;;;;;;;UA+EiB,iBAAA,mBAAoC,gBAAA,UAC3C,mBAAA,CAAsB,SAAA,GAAY,eAAA;AAAA,UAE3B,kBAAA,mBAAqC,gBAAA,UAC5C,oBAAA,CAAuB,SAAA,GAAY,eAAA;EAC3C,eAAA,IAAmB,OAAA,CAAQ,cAAA,CAAe,YAAA;EAC1C,UAAA,IAAc,OAAA;AAAA;AAAA,KAGJ,uBAAA,GAA0B,sBAAA,GACpC,mBAAmB;EATX,iFAWN,iBAAA,UAXuD;EAavD,iBAAA;AAAA;AAAA,cAGS,+BAAA,EAAiC,uBAK7C;AAAA,KAEW,gBAAA,gCAAgD,gBAAA,KAC1D,IAAA,EAAM,WAAA,EACN,IAAA,EAAM,WAAA,KACH,cAAA,CAAe,QAAA,CAAS,SAAA;AAAA,cAEhB,oBAAA,gCAEO,gBAAA,aACP,4BAAA,CAA6B,WAAA;EAAA,iBACvB,MAAA;EAAA,iBAEA,iBAAA;EAAA,iBACA,kBAAA;EAAA,iBAEA,eAAA;EAAA,iBAEA,OAAA;EAAA,iBACA,UAAA;EAAA,iBACA,OAAA;EAAA,iBAEA,mBAAA;EAAA,iBACA,gBAAA;EAAA,iBAEA,uBAAA;EAAA,iBACA,uBAAA;EAEJ,SAAA,IAAa,OAAA,CAAQ,UAAA;EAIrB,eAAA,IAAmB,OAAA,CAAQ,cAAA,CAAe,YAAA;EAI1C,UAAA,IAAc,OAAA;;IAKzB,MAAA;IACA,iBAAA;IACA,kBAAA;IACA,SAAA;IACA,OAAA;IACA;EAAA;IAEA,MAAA,GAAS,cAAA,CAAe,MAAA;IACxB,iBAAA,EAAmB,iBAAA,CAAkB,SAAA;IACrC,kBAAA,EAAoB,kBAAA,CAAmB,SAAA;IACvC,SAAA;IACA,OAAA,GAAU,uBAAA;IACV,eAAA,EAAiB,gBAAA,CAAiB,WAAA,EAAa,SAAA;EAAA;EAyB3C,OAAA,IAAW,OAAA;EAAA,CAUV,MAAA,CAAO,YAAA,KAAiB,OAAA;EAQxB,YAAA,CAAa,GAAA,EAAK,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAa9D,YAAA,CAAa,MAAA,EAAQ,SAAA,CAAU,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAsCjE,cAAA,CAAe,GAAA,EAAK,WAAA,CAAY,OAAA,CAAQ,WAAA,KAAgB,SAAA,CAAU,YAAA;EAqC5D,eAAA,CACX,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,wBAAA,GACR,OAAA,CAAQ,uBAAA;
|
|
1
|
+
{"version":3,"file":"driver_impl.d.ts","names":[],"sources":["../src/driver_impl.ts"],"mappings":"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"}
|
package/dist/driver_impl.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getNativeColumnLabel, streamPTableRows } from "./csv_writer.js";
|
|
2
2
|
import { logPFrames } from "./logging.js";
|
|
3
3
|
import { PFramePool } from "./pframe_pool.js";
|
|
4
4
|
import { embedInlineColumnTypeSpecs } from "./ptable_shared.js";
|
|
@@ -150,6 +150,11 @@ var AbstractPFrameDriver = class {
|
|
|
150
150
|
const tableGuard = _usingCtx4.u(new PoolEntryGuard(this.pTables.acquire(def)));
|
|
151
151
|
const { pTablePromise, disposeSignal } = tableGuard.resource;
|
|
152
152
|
const pTable = await pTablePromise;
|
|
153
|
+
const { columnIndices } = options;
|
|
154
|
+
const headerNames = columnIndices.map((index, i) => {
|
|
155
|
+
const name = options.headerNames?.[i];
|
|
156
|
+
return name !== void 0 && name !== "" ? name : getNativeColumnLabel(def.tableSpec[index]);
|
|
157
|
+
});
|
|
153
158
|
const combinedSignal = AbortSignal.any([options.signal, disposeSignal].filter((s) => !isNil(s)));
|
|
154
159
|
const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {
|
|
155
160
|
const shape = await pTable.getShape({ signal: combinedSignal });
|
|
@@ -159,7 +164,8 @@ var AbstractPFrameDriver = class {
|
|
|
159
164
|
const iterable = streamPTableRows({
|
|
160
165
|
pTable,
|
|
161
166
|
specs,
|
|
162
|
-
columnIndices
|
|
167
|
+
columnIndices,
|
|
168
|
+
headerNames,
|
|
163
169
|
range: clippedRange,
|
|
164
170
|
chunkSize: options.chunkSize ?? 5e4,
|
|
165
171
|
separator,
|
|
@@ -184,7 +190,7 @@ var AbstractPFrameDriver = class {
|
|
|
184
190
|
const rowsWritten = clippedRange.length;
|
|
185
191
|
if (logPFrames()) {
|
|
186
192
|
const durationMs = Math.round(performance.now() - startTime);
|
|
187
|
-
this.logger("info", `[WritePTableToFs] complete (handle = ${handle}, columns = ${
|
|
193
|
+
this.logger("info", `[WritePTableToFs] complete (handle = ${handle}, columns = ${columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`);
|
|
188
194
|
}
|
|
189
195
|
return {
|
|
190
196
|
result: {
|
|
@@ -214,7 +220,10 @@ var AbstractPFrameDriver = class {
|
|
|
214
220
|
const { pTablePromise, disposeSignal } = tableGuard.resource;
|
|
215
221
|
const pTable = await pTablePromise;
|
|
216
222
|
const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !isNil(s)));
|
|
217
|
-
const headers = columnIndices.map((index) =>
|
|
223
|
+
const headers = columnIndices.map((index, i) => {
|
|
224
|
+
const name = options.headerNames?.[i];
|
|
225
|
+
return [index, name !== void 0 && name !== "" ? name : getNativeColumnLabel(def.tableSpec[index])];
|
|
226
|
+
});
|
|
218
227
|
const overallSize = await this.tableConcurrencyLimiter.run(async () => {
|
|
219
228
|
if (path.toLowerCase().endsWith(".xlsx")) {
|
|
220
229
|
const shape = await pTable.getShape({ signal: combinedSignal });
|
package/dist/driver_impl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_impl.js","names":["fs"],"sources":["../src/driver_impl.ts"],"sourcesContent":["import {\n mapPObjectData,\n mapPTableDef,\n extractAllColumns,\n uniqueBy,\n canonicalizeJson,\n bigintReplacer,\n ValueType,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type FindColumnsRequest,\n type FindColumnsResponse,\n type PColumnIdAndSpec,\n type PColumnSpec,\n type PFrameHandle,\n type PObjectId,\n type PTableColumnSpec,\n type PTableHandle,\n type PTableShape,\n type PTableVector,\n type TableRange,\n type UniqueValuesRequest,\n type UniqueValuesResponse,\n type PColumn,\n type PFrameDef,\n type PTableDef,\n type PTableRecordSingleValueFilterV2,\n type PTableRecordFilter,\n type JsonSerializable,\n type PTableDefV2,\n mapSpecQueryColumns,\n collectSpecQueryColumns,\n sortSpecQuery,\n sortPTableDef,\n resolveAnnotationParents,\n PFrameDriverError,\n XLSX_MAX_ROWS_PER_SHEET,\n} from \"@milaboratories/pl-model-common\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n ConcurrencyLimitingExecutor,\n createPathAtomically,\n type MiLogger,\n} from \"@milaboratories/ts-helpers\";\nimport { isNil, PoolEntryGuard, type PoolEntry } from \"@milaboratories/helpers\";\nimport { PFrameFactory } from \"@milaboratories/pframes-rs-node\";\nimport { expandAxes, findTableColumn, rewriteLegacyFilters } from \"@milaboratories/pframes-rs-wasm\";\nimport { tmpdir } from \"node:os\";\nimport * as fs from \"node:fs\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport * as zlib from \"node:zlib\";\nimport { columnLabel, streamPTableRows } from \"./csv_writer\";\nimport type {\n AbstractInternalPFrameDriver,\n WritePTableToFsOptions,\n WritePTableToFsResult,\n ExportPTableOptions,\n} from \"./driver_decl\";\nimport { logPFrames } from \"./logging\";\nimport {\n PFramePool,\n type LocalBlobProvider as PoolLocalBlobProvider,\n type RemoteBlobProvider as PoolRemoteBlobProvider,\n} from \"./pframe_pool\";\nimport { PTableDefPool } from \"./ptable_def_pool\";\nimport { PTablePool } from \"./ptable_pool\";\nimport { embedInlineColumnTypeSpecs } from \"./ptable_shared\";\nimport {\n PTableCachePerFrame,\n PTableCachePerFrameOpsDefaults,\n type PTableCachePerFrameOps,\n} from \"./ptable_cache_per_frame\";\nimport {\n PTableCachePlain,\n PTableCachePlainOpsDefaults,\n type PTableCachePlainOps,\n} from \"./ptable_cache_plain\";\n\nexport interface LocalBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolLocalBlobProvider<TreeEntry>, AsyncDisposable {}\n\nexport interface RemoteBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolRemoteBlobProvider<TreeEntry>, AsyncDisposable {\n getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null>;\n resetCache(): Promise<void>;\n}\n\nexport type AbstractPFrameDriverOps = PTableCachePerFrameOps &\n PTableCachePlainOps & {\n /** Concurrency limits for `getUniqueValues` and `calculateTableData` requests */\n pFrameConcurrency: number;\n /** Concurrency limits for `getShape` and `getData` requests */\n pTableConcurrency: number;\n };\n\nexport const AbstractPFrameDriverOpsDefaults: AbstractPFrameDriverOps = {\n ...PTableCachePerFrameOpsDefaults,\n ...PTableCachePlainOpsDefaults,\n pFrameConcurrency: 1, // 1 join is executed in parallel and utilize all RAM and CPU cores\n pTableConcurrency: 1, // 1 joined table is read from disk at a time, which matches 1 table the user can view in the UI\n};\n\nexport type DataInfoResolver<PColumnData, TreeEntry extends JsonSerializable> = (\n spec: PColumnSpec,\n data: PColumnData,\n) => PFrameInternal.DataInfo<TreeEntry>;\n\nexport class AbstractPFrameDriver<\n PColumnData,\n TreeEntry extends JsonSerializable,\n> implements AbstractInternalPFrameDriver<PColumnData> {\n private readonly logger: PFrameInternal.Logger;\n\n private readonly localBlobProvider: LocalBlobProvider<TreeEntry>;\n private readonly remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n\n private readonly resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n\n private readonly pFrames: PFramePool<TreeEntry>;\n private readonly pTableDefs: PTableDefPool;\n private readonly pTables: PTablePool<TreeEntry>;\n\n private readonly pTableCachePerFrame: PTableCachePerFrame;\n private readonly pTableCachePlain: PTableCachePlain;\n\n private readonly frameConcurrencyLimiter: ConcurrencyLimitingExecutor;\n private readonly tableConcurrencyLimiter: ConcurrencyLimitingExecutor;\n\n public async pprofDump(): Promise<Uint8Array> {\n return await PFrameFactory.pprofDump();\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return await this.remoteBlobProvider.getCacheMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.remoteBlobProvider.resetCache();\n }\n\n public constructor({\n logger = () => {},\n localBlobProvider,\n remoteBlobProvider,\n spillPath = tmpdir(),\n options = AbstractPFrameDriverOpsDefaults,\n resolveDataInfo,\n }: {\n logger?: PFrameInternal.Logger;\n localBlobProvider: LocalBlobProvider<TreeEntry>;\n remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n spillPath?: string;\n options?: AbstractPFrameDriverOps;\n resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n }) {\n this.logger = logger;\n\n this.localBlobProvider = localBlobProvider;\n this.remoteBlobProvider = remoteBlobProvider;\n\n this.resolveDataInfo = resolveDataInfo;\n\n this.frameConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pFrameConcurrency);\n this.tableConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pTableConcurrency);\n\n this.pFrames = new PFramePool(\n this.localBlobProvider,\n this.remoteBlobProvider,\n this.logger,\n spillPath,\n );\n this.pTableDefs = new PTableDefPool(this.logger);\n this.pTables = new PTablePool(this.pFrames, this.pTableDefs, this.logger);\n\n this.pTableCachePerFrame = new PTableCachePerFrame(this.logger, options);\n this.pTableCachePlain = new PTableCachePlain(this.logger, options);\n }\n\n async dispose(): Promise<void> {\n void (await Promise.allSettled([\n this.pTables[Symbol.asyncDispose](),\n this.pTableDefs[Symbol.asyncDispose](),\n this.pFrames[Symbol.asyncDispose](),\n this.localBlobProvider[Symbol.asyncDispose](),\n this.remoteBlobProvider[Symbol.asyncDispose](),\n ]));\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n return await this.dispose();\n }\n\n //\n // Internal / Config API Methods\n //\n\n public createPFrame(def: PFrameDef<PColumn<PColumnData>>): PoolEntry<PFrameHandle> {\n const ValueTypes = new Set(Object.values(ValueType));\n const supportedColumns = def\n .filter((column) => ValueTypes.has(column.spec.valueType))\n .map((c) => ({ ...c, spec: resolveAnnotationParents(c.spec) }));\n const uniqueColumns = uniqueBy(supportedColumns, (column) => column.id);\n const columns = uniqueColumns.map((c) =>\n mapPObjectData(c, (d) => this.resolveDataInfo(c.spec, d)),\n );\n\n return this.pFrames.acquire(columns);\n }\n\n public createPTable(rawDef: PTableDef<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(extractAllColumns(rawDef.src), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const sortedDef = sortPTableDef(\n migrateTableFilter(\n mapPTableDef(rawDef, (c) => c.id),\n this.logger,\n ),\n );\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquireFromLegacy({\n pFrameHandle: pFrameGuard.key,\n def: sortedDef,\n pFrameSpec,\n }).entry,\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public createPTableV2(def: PTableDefV2<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(collectSpecQueryColumns(def.query), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n const sortedQuery = sortSpecQuery(mapSpecQueryColumns(def.query, { column: (c) => c.id }));\n const { tableSpec, dataQuery } = pFrameSpec.evaluateQuery(\n embedInlineColumnTypeSpecs(sortedQuery),\n );\n\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquire({\n pFrameHandle: pFrameGuard.key,\n tableSpec,\n dataQuery,\n }),\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public async writePTableToFs(\n handle: PTableHandle,\n options: WritePTableToFsOptions,\n ): Promise<WritePTableToFsResult> {\n this.logger(\n \"info\",\n `[WritePTableToFs] ENTER (handle = ${handle}, path = ${options.path}, format = ${options.format}, compression = ${options.compression ?? \"auto\"}, columns = ${options.columnIndices.length})`,\n );\n const startTime = performance.now();\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [options.signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // `combinedSignal` is passed twice on purpose: into the native calls for cooperative\n // cancellation, and into `run` so the concurrency slot is released on abort even if a\n // native call fails to unwind. Dropping the `run` signal reintroduces the queue wedge.\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({ signal: combinedSignal });\n const clippedRange = clipRange(options.range, shape);\n const specs = def.tableSpec;\n const separator = options.format === \"tsv\" ? \"\\t\" : \",\";\n\n const iterable = streamPTableRows({\n pTable,\n specs,\n columnIndices: options.columnIndices,\n range: clippedRange,\n chunkSize: options.chunkSize ?? 50_000,\n separator,\n includeHeader: options.includeHeader ?? true,\n bom: options.bom ?? true,\n signal: combinedSignal,\n });\n\n const miLogger: MiLogger = {\n info: (msg) => this.logger(\"info\", String(msg)),\n warn: (msg) => this.logger(\"warn\", String(msg)),\n error: (msg) => this.logger(\"error\", String(msg)),\n };\n\n let bytesWritten = 0;\n await createPathAtomically(miLogger, options.path, async (tempPath) => {\n const writeStream = fs.createWriteStream(tempPath, { flags: \"wx\" });\n const source = Readable.from(iterable, { objectMode: false });\n if (options.compression?.type === \"gzip\") {\n const gzip = zlib.createGzip({ level: options.compression.level ?? 6 });\n await pipeline(source, gzip, writeStream, { signal: combinedSignal });\n } else {\n await pipeline(source, writeStream, { signal: combinedSignal });\n }\n bytesWritten = writeStream.bytesWritten;\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n // rowsWritten equals the clipped range length — the generator streams the\n // entire effective range without early termination, so this is accurate.\n const rowsWritten = clippedRange.length;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[WritePTableToFs] complete (handle = ${handle}, columns = ${options.columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,\n );\n }\n\n return { result: { path: options.path, rowsWritten, bytesWritten }, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return result;\n }\n\n public async exportPTable(\n handle: PTableHandle,\n options: ExportPTableOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { path, columnIndices } = options;\n\n this.logger(\"info\", `[ExportPTable] ENTER (handle = ${handle}, path = ${path})`);\n const startTime = performance.now();\n\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n const headers: [number, string][] = columnIndices.map((index): [number, string] => [\n index,\n columnLabel(def.tableSpec[index]),\n ]);\n\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const overallSize = await this.tableConcurrencyLimiter.run(async () => {\n // Cap data rows per xlsx sheet below Excel's hard limit of 1,048,576.\n if (path.toLowerCase().endsWith(\".xlsx\")) {\n const shape = await pTable.getShape({ signal: combinedSignal });\n if (shape.rows > XLSX_MAX_ROWS_PER_SHEET) {\n const error = new PFrameDriverError(`exportPTable failed`);\n error.cause = new Error(\n `xlsx export rejected: ${shape.rows} rows exceed the per-sheet ` +\n `limit of ${XLSX_MAX_ROWS_PER_SHEET} rows`,\n );\n throw error;\n }\n }\n\n await pTable.export(path, { headers, signal: combinedSignal });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[ExportPTable] complete (handle = ${handle}, path = ${path}), ` +\n `duration = ${durationMs}ms`,\n );\n }\n\n return overallSize;\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n }\n\n //\n // PFrame instance methods\n //\n\n public async findColumns(\n handle: PFrameHandle,\n request: FindColumnsRequest,\n ): Promise<FindColumnsResponse> {\n const iRequest: PFrameInternal.FindColumnsRequest = {\n ...request,\n compatibleWith:\n request.compatibleWith.length !== 0\n ? [\n {\n axesSpec: [\n ...new Map(\n request.compatibleWith.map((item) => [canonicalizeJson(item), item] as const),\n ).values(),\n ],\n qualifications: [],\n },\n ]\n : [],\n };\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const response = pFrameSpec.findColumns(iRequest);\n return {\n hits: response.hits\n .filter(\n (h) =>\n // only exactly matching columns\n h.mappingVariants.length === 0 ||\n h.mappingVariants.some(\n (v) =>\n v.qualifications.forHit.length === 0 &&\n v.qualifications.forQueries.every((q) => q.length === 0),\n ),\n )\n .map((h) => h.hit),\n };\n }\n\n public async getColumnSpec(\n handle: PFrameHandle,\n columnId: PObjectId,\n ): Promise<PColumnSpec | null> {\n const { columnSpecs } = this.pFrames.getByKey(handle);\n return columnSpecs[columnId] ?? null;\n }\n\n public async listColumns(handle: PFrameHandle): Promise<PColumnIdAndSpec[]> {\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n return pFrameSpec.listColumns().map(({ columnId, spec }) => ({ columnId, spec }));\n }\n\n public async calculateTableData(\n handle: PFrameHandle,\n request: CalculateTableDataRequest<PObjectId>,\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<CalculateTableDataResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call calculateTableData, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const sortedDef = sortPTableDef(migrateTableFilter(request, this.logger));\n const { def, entry } = this.pTables.acquireFromLegacy({\n pFrameHandle: handle,\n def: sortedDef,\n pFrameSpec,\n });\n using tableGuard = new PoolEntryGuard(entry);\n const tableSpec = def.tableSpec;\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { data, overallSize } = await this.frameConcurrencyLimiter.run(async () => {\n // TODO: throw error when more then 200k rows is requested\n // after pf-plots migration to stream API\n\n const data = await pTable.getData([...tableSpec.keys()], {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePerFrame.cache(tableGuard.keep(), overallSize);\n return tableSpec.map((spec, i) => ({\n spec: spec,\n data: data[i],\n }));\n }\n\n public async getUniqueValues(\n handle: PFrameHandle,\n request: UniqueValuesRequest,\n signal?: AbortSignal,\n ): Promise<UniqueValuesResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call getUniqueValues, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameDataPromise, columnSpecs, disposeSignal } = this.pFrames.getByKey(handle);\n const pFrameData = await pFrameDataPromise;\n\n const columnSpec = columnSpecs[request.columnId];\n if (!columnSpec) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(`column ${request.columnId} is not registered in the PFrame`);\n throw error;\n }\n\n const axisIds = expandAxes(columnSpec.axesSpec);\n const tableSpec: PTableColumnSpec[] = [\n ...columnSpec.axesSpec.map(\n (axisSpec, i): PTableColumnSpec => ({\n type: \"axis\",\n id: axisIds[i],\n spec: axisSpec,\n }),\n ),\n { type: \"column\", id: request.columnId, spec: columnSpec },\n ];\n\n let axisIndex: number | undefined;\n if (request.axis !== undefined) {\n const index = findTableColumn(tableSpec, { type: \"axis\", id: request.axis });\n if (index < 0) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(\n `axis ${JSON.stringify(request.axis)} not found among axes of column ${request.columnId}`,\n );\n throw error;\n }\n axisIndex = index;\n }\n\n const resolvedRequest: PFrameInternal.UniqueValuesRequestV2 = {\n columnId: request.columnId,\n axisIndex,\n filters: rewriteLegacyFilters({\n tableSpec,\n filters: migrateFilters(request.filters, this.logger),\n }),\n limit: request.limit,\n };\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n return await this.frameConcurrencyLimiter.run(async () => {\n return await pFrameData.getUniqueValues(resolvedRequest, { signal: combinedSignal });\n }, combinedSignal);\n }\n\n //\n // PTable instance methods\n //\n\n public async getSpec(handle: PTableHandle): Promise<PTableColumnSpec[]> {\n const { def } = this.pTableDefs.getByKey(handle);\n return def.tableSpec;\n }\n\n public async getShape(handle: PTableHandle, signal?: AbortSignal): Promise<PTableShape> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { shape, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { shape, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return shape;\n }\n\n public async getData(\n handle: PTableHandle,\n columnIndices: number[],\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<PTableVector[]> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { data, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const data = await pTable.getData(columnIndices, {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return data;\n }\n}\n\n/** Clamp range to table shape. When range is undefined, returns full table range. */\nfunction clipRange(range: undefined | TableRange, shape: PTableShape): TableRange {\n if (isNil(range)) {\n return { offset: 0, length: shape.rows };\n }\n const clampedOffset = Math.min(range.offset, shape.rows);\n const clampedLength = Math.min(range.length, shape.rows - clampedOffset);\n return { offset: clampedOffset, length: clampedLength };\n}\n\nfunction migrateFilters(\n filters: PTableRecordFilter[],\n logger: PFrameInternal.Logger,\n): PTableRecordFilter[] {\n const filtersV1 = [];\n const filtersV2: PTableRecordSingleValueFilterV2[] = [];\n for (const filter of filters) {\n if ((filter.type as unknown) === \"bySingleColumn\") {\n filtersV1.push(filter);\n filtersV2.push({\n ...filter,\n type: \"bySingleColumnV2\",\n });\n } else {\n filtersV2.push(filter);\n }\n }\n if (filtersV1.length > 0) {\n const filtersV1Json = JSON.stringify(filtersV1);\n logger(\n \"warn\",\n `type overwritten from 'bySingleColumn' to 'bySingleColumnV2' for filters: ${filtersV1Json}`,\n );\n }\n return filtersV2;\n}\n\nfunction migrateTableFilter<T>(\n def: Omit<PTableDef<T>, \"partitionFilters\"> | PTableDef<T>,\n logger: PFrameInternal.Logger,\n): PTableDef<T> {\n if (!(\"partitionFilters\" in def)) {\n // For old blocks assume all axes filters to be partition filters\n return {\n ...def,\n partitionFilters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"axis\"),\n logger,\n ),\n filters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"column\"),\n logger,\n ),\n };\n }\n return {\n ...def,\n partitionFilters: migrateFilters(def.partitionFilters, logger),\n filters: migrateFilters(def.filters, logger),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"driver_impl.js","names":["fs"],"sources":["../src/driver_impl.ts"],"sourcesContent":["import {\n mapPObjectData,\n mapPTableDef,\n extractAllColumns,\n uniqueBy,\n canonicalizeJson,\n bigintReplacer,\n ValueType,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type FindColumnsRequest,\n type FindColumnsResponse,\n type PColumnIdAndSpec,\n type PColumnSpec,\n type PFrameHandle,\n type PObjectId,\n type PTableColumnSpec,\n type PTableHandle,\n type PTableShape,\n type PTableVector,\n type TableRange,\n type UniqueValuesRequest,\n type UniqueValuesResponse,\n type PColumn,\n type PFrameDef,\n type PTableDef,\n type PTableRecordSingleValueFilterV2,\n type PTableRecordFilter,\n type JsonSerializable,\n type PTableDefV2,\n mapSpecQueryColumns,\n collectSpecQueryColumns,\n sortSpecQuery,\n sortPTableDef,\n resolveAnnotationParents,\n PFrameDriverError,\n XLSX_MAX_ROWS_PER_SHEET,\n} from \"@milaboratories/pl-model-common\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n ConcurrencyLimitingExecutor,\n createPathAtomically,\n type MiLogger,\n} from \"@milaboratories/ts-helpers\";\nimport { isNil, PoolEntryGuard, type PoolEntry } from \"@milaboratories/helpers\";\nimport { PFrameFactory } from \"@milaboratories/pframes-rs-node\";\nimport { expandAxes, findTableColumn, rewriteLegacyFilters } from \"@milaboratories/pframes-rs-wasm\";\nimport { tmpdir } from \"node:os\";\nimport * as fs from \"node:fs\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport * as zlib from \"node:zlib\";\nimport { getNativeColumnLabel, streamPTableRows } from \"./csv_writer\";\nimport type {\n AbstractInternalPFrameDriver,\n WritePTableToFsOptions,\n WritePTableToFsResult,\n ExportPTableOptions,\n} from \"./driver_decl\";\nimport { logPFrames } from \"./logging\";\nimport {\n PFramePool,\n type LocalBlobProvider as PoolLocalBlobProvider,\n type RemoteBlobProvider as PoolRemoteBlobProvider,\n} from \"./pframe_pool\";\nimport { PTableDefPool } from \"./ptable_def_pool\";\nimport { PTablePool } from \"./ptable_pool\";\nimport { embedInlineColumnTypeSpecs } from \"./ptable_shared\";\nimport {\n PTableCachePerFrame,\n PTableCachePerFrameOpsDefaults,\n type PTableCachePerFrameOps,\n} from \"./ptable_cache_per_frame\";\nimport {\n PTableCachePlain,\n PTableCachePlainOpsDefaults,\n type PTableCachePlainOps,\n} from \"./ptable_cache_plain\";\n\nexport interface LocalBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolLocalBlobProvider<TreeEntry>, AsyncDisposable {}\n\nexport interface RemoteBlobProvider<TreeEntry extends JsonSerializable>\n extends PoolRemoteBlobProvider<TreeEntry>, AsyncDisposable {\n getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null>;\n resetCache(): Promise<void>;\n}\n\nexport type AbstractPFrameDriverOps = PTableCachePerFrameOps &\n PTableCachePlainOps & {\n /** Concurrency limits for `getUniqueValues` and `calculateTableData` requests */\n pFrameConcurrency: number;\n /** Concurrency limits for `getShape` and `getData` requests */\n pTableConcurrency: number;\n };\n\nexport const AbstractPFrameDriverOpsDefaults: AbstractPFrameDriverOps = {\n ...PTableCachePerFrameOpsDefaults,\n ...PTableCachePlainOpsDefaults,\n pFrameConcurrency: 1, // 1 join is executed in parallel and utilize all RAM and CPU cores\n pTableConcurrency: 1, // 1 joined table is read from disk at a time, which matches 1 table the user can view in the UI\n};\n\nexport type DataInfoResolver<PColumnData, TreeEntry extends JsonSerializable> = (\n spec: PColumnSpec,\n data: PColumnData,\n) => PFrameInternal.DataInfo<TreeEntry>;\n\nexport class AbstractPFrameDriver<\n PColumnData,\n TreeEntry extends JsonSerializable,\n> implements AbstractInternalPFrameDriver<PColumnData> {\n private readonly logger: PFrameInternal.Logger;\n\n private readonly localBlobProvider: LocalBlobProvider<TreeEntry>;\n private readonly remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n\n private readonly resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n\n private readonly pFrames: PFramePool<TreeEntry>;\n private readonly pTableDefs: PTableDefPool;\n private readonly pTables: PTablePool<TreeEntry>;\n\n private readonly pTableCachePerFrame: PTableCachePerFrame;\n private readonly pTableCachePlain: PTableCachePlain;\n\n private readonly frameConcurrencyLimiter: ConcurrencyLimitingExecutor;\n private readonly tableConcurrencyLimiter: ConcurrencyLimitingExecutor;\n\n public async pprofDump(): Promise<Uint8Array> {\n return await PFrameFactory.pprofDump();\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return await this.remoteBlobProvider.getCacheMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.remoteBlobProvider.resetCache();\n }\n\n public constructor({\n logger = () => {},\n localBlobProvider,\n remoteBlobProvider,\n spillPath = tmpdir(),\n options = AbstractPFrameDriverOpsDefaults,\n resolveDataInfo,\n }: {\n logger?: PFrameInternal.Logger;\n localBlobProvider: LocalBlobProvider<TreeEntry>;\n remoteBlobProvider: RemoteBlobProvider<TreeEntry>;\n spillPath?: string;\n options?: AbstractPFrameDriverOps;\n resolveDataInfo: DataInfoResolver<PColumnData, TreeEntry>;\n }) {\n this.logger = logger;\n\n this.localBlobProvider = localBlobProvider;\n this.remoteBlobProvider = remoteBlobProvider;\n\n this.resolveDataInfo = resolveDataInfo;\n\n this.frameConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pFrameConcurrency);\n this.tableConcurrencyLimiter = new ConcurrencyLimitingExecutor(options.pTableConcurrency);\n\n this.pFrames = new PFramePool(\n this.localBlobProvider,\n this.remoteBlobProvider,\n this.logger,\n spillPath,\n );\n this.pTableDefs = new PTableDefPool(this.logger);\n this.pTables = new PTablePool(this.pFrames, this.pTableDefs, this.logger);\n\n this.pTableCachePerFrame = new PTableCachePerFrame(this.logger, options);\n this.pTableCachePlain = new PTableCachePlain(this.logger, options);\n }\n\n async dispose(): Promise<void> {\n void (await Promise.allSettled([\n this.pTables[Symbol.asyncDispose](),\n this.pTableDefs[Symbol.asyncDispose](),\n this.pFrames[Symbol.asyncDispose](),\n this.localBlobProvider[Symbol.asyncDispose](),\n this.remoteBlobProvider[Symbol.asyncDispose](),\n ]));\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n return await this.dispose();\n }\n\n //\n // Internal / Config API Methods\n //\n\n public createPFrame(def: PFrameDef<PColumn<PColumnData>>): PoolEntry<PFrameHandle> {\n const ValueTypes = new Set(Object.values(ValueType));\n const supportedColumns = def\n .filter((column) => ValueTypes.has(column.spec.valueType))\n .map((c) => ({ ...c, spec: resolveAnnotationParents(c.spec) }));\n const uniqueColumns = uniqueBy(supportedColumns, (column) => column.id);\n const columns = uniqueColumns.map((c) =>\n mapPObjectData(c, (d) => this.resolveDataInfo(c.spec, d)),\n );\n\n return this.pFrames.acquire(columns);\n }\n\n public createPTable(rawDef: PTableDef<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(extractAllColumns(rawDef.src), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const sortedDef = sortPTableDef(\n migrateTableFilter(\n mapPTableDef(rawDef, (c) => c.id),\n this.logger,\n ),\n );\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquireFromLegacy({\n pFrameHandle: pFrameGuard.key,\n def: sortedDef,\n pFrameSpec,\n }).entry,\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public createPTableV2(def: PTableDefV2<PColumn<PColumnData>>): PoolEntry<PTableHandle> {\n const columns = uniqueBy(collectSpecQueryColumns(def.query), (c) => c.id);\n using pFrameGuard = new PoolEntryGuard(this.createPFrame(columns));\n const pFrameSpec = this.pFrames.getByKey(pFrameGuard.key).pFrameSpec;\n const sortedQuery = sortSpecQuery(mapSpecQueryColumns(def.query, { column: (c) => c.id }));\n const { tableSpec, dataQuery } = pFrameSpec.evaluateQuery(\n embedInlineColumnTypeSpecs(sortedQuery),\n );\n\n using pTableGuard = new PoolEntryGuard(\n this.pTableDefs.acquire({\n pFrameHandle: pFrameGuard.key,\n tableSpec,\n dataQuery,\n }),\n );\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Create PTable call (pFrameHandle = ${pFrameGuard.key}; pTableHandle = ${pTableGuard.key})`,\n );\n }\n\n const pFrameEntry = pFrameGuard.keep();\n const pTableEntry = pTableGuard.keep();\n const unref = () => {\n pTableEntry.unref();\n pFrameEntry.unref();\n };\n return {\n key: pTableEntry.key,\n resource: pTableEntry.resource,\n unref,\n [Symbol.dispose]: unref,\n };\n }\n\n public async writePTableToFs(\n handle: PTableHandle,\n options: WritePTableToFsOptions,\n ): Promise<WritePTableToFsResult> {\n this.logger(\n \"info\",\n `[WritePTableToFs] ENTER (handle = ${handle}, path = ${options.path}, format = ${options.format}, compression = ${options.compression ?? \"auto\"}, columns = ${options.columnIndices.length})`,\n );\n const startTime = performance.now();\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n // Caller-supplied header names win (they carry the disambiguated labels the\n // UI shows); a missing or empty name falls back to the spec-derived label.\n const { columnIndices } = options;\n const headerNames = columnIndices.map((index, i) => {\n const name = options.headerNames?.[i];\n return name !== undefined && name !== \"\" ? name : getNativeColumnLabel(def.tableSpec[index]);\n });\n\n const combinedSignal = AbortSignal.any(\n [options.signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // `combinedSignal` is passed twice on purpose: into the native calls for cooperative\n // cancellation, and into `run` so the concurrency slot is released on abort even if a\n // native call fails to unwind. Dropping the `run` signal reintroduces the queue wedge.\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { result, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({ signal: combinedSignal });\n const clippedRange = clipRange(options.range, shape);\n const specs = def.tableSpec;\n const separator = options.format === \"tsv\" ? \"\\t\" : \",\";\n\n const iterable = streamPTableRows({\n pTable,\n specs,\n columnIndices,\n headerNames,\n range: clippedRange,\n chunkSize: options.chunkSize ?? 50_000,\n separator,\n includeHeader: options.includeHeader ?? true,\n bom: options.bom ?? true,\n signal: combinedSignal,\n });\n\n const miLogger: MiLogger = {\n info: (msg) => this.logger(\"info\", String(msg)),\n warn: (msg) => this.logger(\"warn\", String(msg)),\n error: (msg) => this.logger(\"error\", String(msg)),\n };\n\n let bytesWritten = 0;\n await createPathAtomically(miLogger, options.path, async (tempPath) => {\n const writeStream = fs.createWriteStream(tempPath, { flags: \"wx\" });\n const source = Readable.from(iterable, { objectMode: false });\n if (options.compression?.type === \"gzip\") {\n const gzip = zlib.createGzip({ level: options.compression.level ?? 6 });\n await pipeline(source, gzip, writeStream, { signal: combinedSignal });\n } else {\n await pipeline(source, writeStream, { signal: combinedSignal });\n }\n bytesWritten = writeStream.bytesWritten;\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n // rowsWritten equals the clipped range length — the generator streams the\n // entire effective range without early termination, so this is accurate.\n const rowsWritten = clippedRange.length;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[WritePTableToFs] complete (handle = ${handle}, columns = ${columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,\n );\n }\n\n return { result: { path: options.path, rowsWritten, bytesWritten }, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return result;\n }\n\n public async exportPTable(\n handle: PTableHandle,\n options: ExportPTableOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { path, columnIndices } = options;\n\n this.logger(\"info\", `[ExportPTable] ENTER (handle = ${handle}, path = ${path})`);\n const startTime = performance.now();\n\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any(\n [signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),\n );\n\n // Caller-supplied header names win (they carry the disambiguated labels the\n // UI shows); a missing or empty name falls back to the spec-derived label.\n const headers: [number, string][] = columnIndices.map((index, i): [number, string] => {\n const name = options.headerNames?.[i];\n return [\n index,\n name !== undefined && name !== \"\" ? name : getNativeColumnLabel(def.tableSpec[index]),\n ];\n });\n\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const overallSize = await this.tableConcurrencyLimiter.run(async () => {\n // Cap data rows per xlsx sheet below Excel's hard limit of 1,048,576.\n if (path.toLowerCase().endsWith(\".xlsx\")) {\n const shape = await pTable.getShape({ signal: combinedSignal });\n if (shape.rows > XLSX_MAX_ROWS_PER_SHEET) {\n const error = new PFrameDriverError(`exportPTable failed`);\n error.cause = new Error(\n `xlsx export rejected: ${shape.rows} rows exceed the per-sheet ` +\n `limit of ${XLSX_MAX_ROWS_PER_SHEET} rows`,\n );\n throw error;\n }\n }\n\n await pTable.export(path, { headers, signal: combinedSignal });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n if (logPFrames()) {\n const durationMs = Math.round(performance.now() - startTime);\n this.logger(\n \"info\",\n `[ExportPTable] complete (handle = ${handle}, path = ${path}), ` +\n `duration = ${durationMs}ms`,\n );\n }\n\n return overallSize;\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n }\n\n //\n // PFrame instance methods\n //\n\n public async findColumns(\n handle: PFrameHandle,\n request: FindColumnsRequest,\n ): Promise<FindColumnsResponse> {\n const iRequest: PFrameInternal.FindColumnsRequest = {\n ...request,\n compatibleWith:\n request.compatibleWith.length !== 0\n ? [\n {\n axesSpec: [\n ...new Map(\n request.compatibleWith.map((item) => [canonicalizeJson(item), item] as const),\n ).values(),\n ],\n qualifications: [],\n },\n ]\n : [],\n };\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const response = pFrameSpec.findColumns(iRequest);\n return {\n hits: response.hits\n .filter(\n (h) =>\n // only exactly matching columns\n h.mappingVariants.length === 0 ||\n h.mappingVariants.some(\n (v) =>\n v.qualifications.forHit.length === 0 &&\n v.qualifications.forQueries.every((q) => q.length === 0),\n ),\n )\n .map((h) => h.hit),\n };\n }\n\n public async getColumnSpec(\n handle: PFrameHandle,\n columnId: PObjectId,\n ): Promise<PColumnSpec | null> {\n const { columnSpecs } = this.pFrames.getByKey(handle);\n return columnSpecs[columnId] ?? null;\n }\n\n public async listColumns(handle: PFrameHandle): Promise<PColumnIdAndSpec[]> {\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n return pFrameSpec.listColumns().map(({ columnId, spec }) => ({ columnId, spec }));\n }\n\n public async calculateTableData(\n handle: PFrameHandle,\n request: CalculateTableDataRequest<PObjectId>,\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<CalculateTableDataResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call calculateTableData, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameSpec } = this.pFrames.getByKey(handle);\n const sortedDef = sortPTableDef(migrateTableFilter(request, this.logger));\n const { def, entry } = this.pTables.acquireFromLegacy({\n pFrameHandle: handle,\n def: sortedDef,\n pFrameSpec,\n });\n using tableGuard = new PoolEntryGuard(entry);\n const tableSpec = def.tableSpec;\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n // keep()/cache live outside the limiter task: on abort `run` rejects and they are\n // skipped, so an abandoned (detached) operation never caches its result nor touches\n // `tableGuard` after the `using` block has already unref'd it.\n const { data, overallSize } = await this.frameConcurrencyLimiter.run(async () => {\n // TODO: throw error when more then 200k rows is requested\n // after pf-plots migration to stream API\n\n const data = await pTable.getData([...tableSpec.keys()], {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePerFrame.cache(tableGuard.keep(), overallSize);\n return tableSpec.map((spec, i) => ({\n spec: spec,\n data: data[i],\n }));\n }\n\n public async getUniqueValues(\n handle: PFrameHandle,\n request: UniqueValuesRequest,\n signal?: AbortSignal,\n ): Promise<UniqueValuesResponse> {\n if (logPFrames()) {\n this.logger(\n \"info\",\n `Call getUniqueValues, handle = ${handle}, request = ${JSON.stringify(request, bigintReplacer)}`,\n );\n }\n\n const { pFrameDataPromise, columnSpecs, disposeSignal } = this.pFrames.getByKey(handle);\n const pFrameData = await pFrameDataPromise;\n\n const columnSpec = columnSpecs[request.columnId];\n if (!columnSpec) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(`column ${request.columnId} is not registered in the PFrame`);\n throw error;\n }\n\n const axisIds = expandAxes(columnSpec.axesSpec);\n const tableSpec: PTableColumnSpec[] = [\n ...columnSpec.axesSpec.map(\n (axisSpec, i): PTableColumnSpec => ({\n type: \"axis\",\n id: axisIds[i],\n spec: axisSpec,\n }),\n ),\n { type: \"column\", id: request.columnId, spec: columnSpec },\n ];\n\n let axisIndex: number | undefined;\n if (request.axis !== undefined) {\n const index = findTableColumn(tableSpec, { type: \"axis\", id: request.axis });\n if (index < 0) {\n const error = new PFrameDriverError(`getUniqueValues failed`);\n error.cause = new Error(\n `axis ${JSON.stringify(request.axis)} not found among axes of column ${request.columnId}`,\n );\n throw error;\n }\n axisIndex = index;\n }\n\n const resolvedRequest: PFrameInternal.UniqueValuesRequestV2 = {\n columnId: request.columnId,\n axisIndex,\n filters: rewriteLegacyFilters({\n tableSpec,\n filters: migrateFilters(request.filters, this.logger),\n }),\n limit: request.limit,\n };\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n return await this.frameConcurrencyLimiter.run(async () => {\n return await pFrameData.getUniqueValues(resolvedRequest, { signal: combinedSignal });\n }, combinedSignal);\n }\n\n //\n // PTable instance methods\n //\n\n public async getSpec(handle: PTableHandle): Promise<PTableColumnSpec[]> {\n const { def } = this.pTableDefs.getByKey(handle);\n return def.tableSpec;\n }\n\n public async getShape(handle: PTableHandle, signal?: AbortSignal): Promise<PTableShape> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { shape, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const shape = await pTable.getShape({\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { shape, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return shape;\n }\n\n public async getData(\n handle: PTableHandle,\n columnIndices: number[],\n range: TableRange | undefined,\n signal?: AbortSignal,\n ): Promise<PTableVector[]> {\n const { def, disposeSignal: defDisposeSignal } = this.pTableDefs.getByKey(handle);\n using tableGuard = new PoolEntryGuard(this.pTables.acquire(def));\n\n const { pTablePromise, disposeSignal } = tableGuard.resource;\n const pTable = await pTablePromise;\n\n const combinedSignal = AbortSignal.any([signal, disposeSignal].filter((s) => !!s));\n const { data, overallSize } = await this.tableConcurrencyLimiter.run(async () => {\n const data = await pTable.getData(columnIndices, {\n range,\n signal: combinedSignal,\n });\n\n const overallSize = await tableGuard.resource.cacheSize;\n\n return { data, overallSize };\n }, combinedSignal);\n\n this.pTableCachePlain.cache(tableGuard.keep(), overallSize, defDisposeSignal);\n return data;\n }\n}\n\n/** Clamp range to table shape. When range is undefined, returns full table range. */\nfunction clipRange(range: undefined | TableRange, shape: PTableShape): TableRange {\n if (isNil(range)) {\n return { offset: 0, length: shape.rows };\n }\n const clampedOffset = Math.min(range.offset, shape.rows);\n const clampedLength = Math.min(range.length, shape.rows - clampedOffset);\n return { offset: clampedOffset, length: clampedLength };\n}\n\nfunction migrateFilters(\n filters: PTableRecordFilter[],\n logger: PFrameInternal.Logger,\n): PTableRecordFilter[] {\n const filtersV1 = [];\n const filtersV2: PTableRecordSingleValueFilterV2[] = [];\n for (const filter of filters) {\n if ((filter.type as unknown) === \"bySingleColumn\") {\n filtersV1.push(filter);\n filtersV2.push({\n ...filter,\n type: \"bySingleColumnV2\",\n });\n } else {\n filtersV2.push(filter);\n }\n }\n if (filtersV1.length > 0) {\n const filtersV1Json = JSON.stringify(filtersV1);\n logger(\n \"warn\",\n `type overwritten from 'bySingleColumn' to 'bySingleColumnV2' for filters: ${filtersV1Json}`,\n );\n }\n return filtersV2;\n}\n\nfunction migrateTableFilter<T>(\n def: Omit<PTableDef<T>, \"partitionFilters\"> | PTableDef<T>,\n logger: PFrameInternal.Logger,\n): PTableDef<T> {\n if (!(\"partitionFilters\" in def)) {\n // For old blocks assume all axes filters to be partition filters\n return {\n ...def,\n partitionFilters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"axis\"),\n logger,\n ),\n filters: migrateFilters(\n def.filters.filter((f) => f.column.type === \"column\"),\n logger,\n ),\n };\n }\n return {\n ...def,\n partitionFilters: migrateFilters(def.partitionFilters, logger),\n filters: migrateFilters(def.filters, logger),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgGA,MAAa,kCAA2D;CACtE,GAAG;CACH,GAAG;CACH,mBAAmB;CACnB,mBAAmB;AACrB;AAOA,IAAa,uBAAb,MAGuD;CACrD;CAEA;CACA;CAEA;CAEA;CACA;CACA;CAEA;CACA;CAEA;CACA;CAEA,MAAa,YAAiC;EAC5C,OAAO,MAAM,cAAc,UAAU;CACvC;CAEA,MAAa,kBAA+D;EAC1E,OAAO,MAAM,KAAK,mBAAmB,gBAAgB;CACvD;CAEA,MAAa,aAA4B;EACvC,MAAM,KAAK,mBAAmB,WAAW;CAC3C;CAEA,YAAmB,EACjB,eAAe,CAAC,GAChB,mBACA,oBACA,YAAY,OAAO,GACnB,UAAU,iCACV,mBAQC;EACD,KAAK,SAAS;EAEd,KAAK,oBAAoB;EACzB,KAAK,qBAAqB;EAE1B,KAAK,kBAAkB;EAEvB,KAAK,0BAA0B,IAAI,4BAA4B,QAAQ,iBAAiB;EACxF,KAAK,0BAA0B,IAAI,4BAA4B,QAAQ,iBAAiB;EAExF,KAAK,UAAU,IAAI,WACjB,KAAK,mBACL,KAAK,oBACL,KAAK,QACL,SACF;EACA,KAAK,aAAa,IAAI,cAAc,KAAK,MAAM;EAC/C,KAAK,UAAU,IAAI,WAAW,KAAK,SAAS,KAAK,YAAY,KAAK,MAAM;EAExE,KAAK,sBAAsB,IAAI,oBAAoB,KAAK,QAAQ,OAAO;EACvE,KAAK,mBAAmB,IAAI,iBAAiB,KAAK,QAAQ,OAAO;CACnE;CAEA,MAAM,UAAyB;EAC7B,MAAY,QAAQ,WAAW;GAC7B,KAAK,QAAQ,OAAO,aAAa,CAAC;GAClC,KAAK,WAAW,OAAO,aAAa,CAAC;GACrC,KAAK,QAAQ,OAAO,aAAa,CAAC;GAClC,KAAK,kBAAkB,OAAO,aAAa,CAAC;GAC5C,KAAK,mBAAmB,OAAO,aAAa,CAAC;EAC/C,CAAC;CACH;CAEA,OAAO,OAAO,gBAA+B;EAC3C,OAAO,MAAM,KAAK,QAAQ;CAC5B;CAMA,aAAoB,KAA+D;EACjF,MAAM,aAAa,IAAI,IAAI,OAAO,OAAO,SAAS,CAAC;EAKnD,MAAM,UADgB,SAHG,IACtB,QAAQ,WAAW,WAAW,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CACzD,KAAK,OAAO;GAAE,GAAG;GAAG,MAAM,yBAAyB,EAAE,IAAI;EAAE,EAChB,IAAI,WAAW,OAAO,EACxC,CAAC,CAAC,KAAK,MACjC,eAAe,IAAI,MAAM,KAAK,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAC1D;EAEA,OAAO,KAAK,QAAQ,QAAQ,OAAO;CACrC;CAEA,aAAoB,QAAkE;;;GACpF,MAAM,UAAU,SAAS,kBAAkB,OAAO,GAAG,IAAI,MAAM,EAAE,EAAE;GACnE,MAAM,cAAA,YAAA,EAAc,IAAI,eAAe,KAAK,aAAa,OAAO,CAAC,CAAA;GACjE,MAAM,YAAY,cAChB,mBACE,aAAa,SAAS,MAAM,EAAE,EAAE,GAChC,KAAK,MACP,CACF;GACA,MAAM,aAAa,KAAK,QAAQ,SAAS,YAAY,GAAG,CAAC,CAAC;GAC1D,MAAM,cAAA,YAAA,EAAc,IAAI,eACtB,KAAK,WAAW,kBAAkB;IAChC,cAAc,YAAY;IAC1B,KAAK;IACL;GACF,CAAC,CAAC,CAAC,KACL,CAAA;GACA,IAAI,WAAW,GACb,KAAK,OACH,QACA,sCAAsC,YAAY,IAAI,mBAAmB,YAAY,IAAI,EAC3F;GAGF,MAAM,cAAc,YAAY,KAAK;GACrC,MAAM,cAAc,YAAY,KAAK;GACrC,MAAM,cAAc;IAClB,YAAY,MAAM;IAClB,YAAY,MAAM;GACpB;GACA,OAAO;IACL,KAAK,YAAY;IACjB,UAAU,YAAY;IACtB;KACC,OAAO,UAAU;GACpB;;;;;;CACF;CAEA,eAAsB,KAAiE;;;GACrF,MAAM,UAAU,SAAS,wBAAwB,IAAI,KAAK,IAAI,MAAM,EAAE,EAAE;GACxE,MAAM,cAAA,WAAA,EAAc,IAAI,eAAe,KAAK,aAAa,OAAO,CAAC,CAAA;GACjE,MAAM,aAAa,KAAK,QAAQ,SAAS,YAAY,GAAG,CAAC,CAAC;GAC1D,MAAM,cAAc,cAAc,oBAAoB,IAAI,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,CAAC;GACzF,MAAM,EAAE,WAAW,cAAc,WAAW,cAC1C,2BAA2B,WAAW,CACxC;GAEA,MAAM,cAAA,WAAA,EAAc,IAAI,eACtB,KAAK,WAAW,QAAQ;IACtB,cAAc,YAAY;IAC1B;IACA;GACF,CAAC,CACH,CAAA;GACA,IAAI,WAAW,GACb,KAAK,OACH,QACA,sCAAsC,YAAY,IAAI,mBAAmB,YAAY,IAAI,EAC3F;GAGF,MAAM,cAAc,YAAY,KAAK;GACrC,MAAM,cAAc,YAAY,KAAK;GACrC,MAAM,cAAc;IAClB,YAAY,MAAM;IAClB,YAAY,MAAM;GACpB;GACA,OAAO;IACL,KAAK,YAAY;IACjB,UAAU,YAAY;IACtB;KACC,OAAO,UAAU;GACpB;;;;;;CACF;CAEA,MAAa,gBACX,QACA,SACgC;;;GAChC,KAAK,OACH,QACA,qCAAqC,OAAO,WAAW,QAAQ,KAAK,aAAa,QAAQ,OAAO,kBAAkB,QAAQ,eAAe,OAAO,cAAc,QAAQ,cAAc,OAAO,EAC7L;GACA,MAAM,YAAY,YAAY,IAAI;GAClC,MAAM,EAAE,KAAK,eAAe,qBAAqB,KAAK,WAAW,SAAS,MAAM;GAChF,MAAM,aAAA,WAAA,EAAa,IAAI,eAAe,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAA;GAC/D,MAAM,EAAE,eAAe,kBAAkB,WAAW;GACpD,MAAM,SAAS,MAAM;GAIrB,MAAM,EAAE,kBAAkB;GAC1B,MAAM,cAAc,cAAc,KAAK,OAAO,MAAM;IAClD,MAAM,OAAO,QAAQ,cAAc;IACnC,OAAO,SAAS,KAAA,KAAa,SAAS,KAAK,OAAO,qBAAqB,IAAI,UAAU,MAAM;GAC7F,CAAC;GAED,MAAM,iBAAiB,YAAY,IACjC,CAAC,QAAQ,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAwB,CAAC,MAAM,CAAC,CAAC,CAC3E;GAQA,MAAM,EAAE,QAAQ,gBAAgB,MAAM,KAAK,wBAAwB,IAAI,YAAY;IACjF,MAAM,QAAQ,MAAM,OAAO,SAAS,EAAE,QAAQ,eAAe,CAAC;IAC9D,MAAM,eAAe,UAAU,QAAQ,OAAO,KAAK;IACnD,MAAM,QAAQ,IAAI;IAClB,MAAM,YAAY,QAAQ,WAAW,QAAQ,MAAO;IAEpD,MAAM,WAAW,iBAAiB;KAChC;KACA;KACA;KACA;KACA,OAAO;KACP,WAAW,QAAQ,aAAa;KAChC;KACA,eAAe,QAAQ,iBAAiB;KACxC,KAAK,QAAQ,OAAO;KACpB,QAAQ;IACV,CAAC;IAED,MAAM,WAAqB;KACzB,OAAO,QAAQ,KAAK,OAAO,QAAQ,OAAO,GAAG,CAAC;KAC9C,OAAO,QAAQ,KAAK,OAAO,QAAQ,OAAO,GAAG,CAAC;KAC9C,QAAQ,QAAQ,KAAK,OAAO,SAAS,OAAO,GAAG,CAAC;IAClD;IAEA,IAAI,eAAe;IACnB,MAAM,qBAAqB,UAAU,QAAQ,MAAM,OAAO,aAAa;KACrE,MAAM,cAAcA,KAAG,kBAAkB,UAAU,EAAE,OAAO,KAAK,CAAC;KAClE,MAAM,SAAS,SAAS,KAAK,UAAU,EAAE,YAAY,MAAM,CAAC;KAC5D,IAAI,QAAQ,aAAa,SAAS,QAEhC,MAAM,SAAS,QADF,KAAK,WAAW,EAAE,OAAO,QAAQ,YAAY,SAAS,EAAE,CAC3C,GAAG,aAAa,EAAE,QAAQ,eAAe,CAAC;UAEpE,MAAM,SAAS,QAAQ,aAAa,EAAE,QAAQ,eAAe,CAAC;KAEhE,eAAe,YAAY;IAC7B,CAAC;IAED,MAAM,cAAc,MAAM,WAAW,SAAS;IAI9C,MAAM,cAAc,aAAa;IAEjC,IAAI,WAAW,GAAG;KAChB,MAAM,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;KAC3D,KAAK,OACH,QACA,wCAAwC,OAAO,cAAc,cAAc,OAAO,WAAW,YAAY,YAAY,aAAa,eAAe,WAAW,IAC9J;IACF;IAEA,OAAO;KAAE,QAAQ;MAAE,MAAM,QAAQ;MAAM;MAAa;KAAa;KAAG;IAAY;GAClF,GAAG,cAAc;GAEjB,KAAK,iBAAiB,MAAM,WAAW,KAAK,GAAG,aAAa,gBAAgB;GAC5E,OAAO;;;;;;CACT;CAEA,MAAa,aACX,QACA,SACA,QACe;;;GACf,MAAM,EAAE,MAAM,kBAAkB;GAEhC,KAAK,OAAO,QAAQ,kCAAkC,OAAO,WAAW,KAAK,EAAE;GAC/E,MAAM,YAAY,YAAY,IAAI;GAElC,MAAM,EAAE,KAAK,eAAe,qBAAqB,KAAK,WAAW,SAAS,MAAM;GAChF,MAAM,aAAA,WAAA,EAAa,IAAI,eAAe,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAA;GAC/D,MAAM,EAAE,eAAe,kBAAkB,WAAW;GACpD,MAAM,SAAS,MAAM;GAErB,MAAM,iBAAiB,YAAY,IACjC,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAwB,CAAC,MAAM,CAAC,CAAC,CACnE;GAIA,MAAM,UAA8B,cAAc,KAAK,OAAO,MAAwB;IACpF,MAAM,OAAO,QAAQ,cAAc;IACnC,OAAO,CACL,OACA,SAAS,KAAA,KAAa,SAAS,KAAK,OAAO,qBAAqB,IAAI,UAAU,MAAM,CACtF;GACF,CAAC;GAKD,MAAM,cAAc,MAAM,KAAK,wBAAwB,IAAI,YAAY;IAErE,IAAI,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,GAAG;KACxC,MAAM,QAAQ,MAAM,OAAO,SAAS,EAAE,QAAQ,eAAe,CAAC;KAC9D,IAAI,MAAM,OAAO,yBAAyB;MACxC,MAAM,QAAQ,IAAI,kBAAkB,qBAAqB;MACzD,MAAM,wBAAQ,IAAI,MAChB,yBAAyB,MAAM,KAAK,sCACtB,wBAAwB,MACxC;MACA,MAAM;KACR;IACF;IAEA,MAAM,OAAO,OAAO,MAAM;KAAE;KAAS,QAAQ;IAAe,CAAC;IAE7D,MAAM,cAAc,MAAM,WAAW,SAAS;IAE9C,IAAI,WAAW,GAAG;KAChB,MAAM,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;KAC3D,KAAK,OACH,QACA,qCAAqC,OAAO,WAAW,KAAK,gBAC5C,WAAW,GAC7B;IACF;IAEA,OAAO;GACT,GAAG,cAAc;GAEjB,KAAK,iBAAiB,MAAM,WAAW,KAAK,GAAG,aAAa,gBAAgB;;;;;;CAC9E;CAMA,MAAa,YACX,QACA,SAC8B;EAC9B,MAAM,WAA8C;GAClD,GAAG;GACH,gBACE,QAAQ,eAAe,WAAW,IAC9B,CACE;IACE,UAAU,CACR,GAAG,IAAI,IACL,QAAQ,eAAe,KAAK,SAAS,CAAC,iBAAiB,IAAI,GAAG,IAAI,CAAU,CAC9E,CAAC,CAAC,OAAO,CACX;IACA,gBAAgB,CAAC;GACnB,CACF,IACA,CAAC;EACT;EAEA,MAAM,EAAE,eAAe,KAAK,QAAQ,SAAS,MAAM;EAEnD,OAAO,EACL,MAFe,WAAW,YAAY,QAEzB,CAAC,CAAC,KACZ,QACE,MAEC,EAAE,gBAAgB,WAAW,KAC7B,EAAE,gBAAgB,MACf,MACC,EAAE,eAAe,OAAO,WAAW,KACnC,EAAE,eAAe,WAAW,OAAO,MAAM,EAAE,WAAW,CAAC,CAC3D,CACJ,CAAC,CACA,KAAK,MAAM,EAAE,GAAG,EACrB;CACF;CAEA,MAAa,cACX,QACA,UAC6B;EAC7B,MAAM,EAAE,gBAAgB,KAAK,QAAQ,SAAS,MAAM;EACpD,OAAO,YAAY,aAAa;CAClC;CAEA,MAAa,YAAY,QAAmD;EAC1E,MAAM,EAAE,eAAe,KAAK,QAAQ,SAAS,MAAM;EACnD,OAAO,WAAW,YAAY,CAAC,CAAC,KAAK,EAAE,UAAU,YAAY;GAAE;GAAU;EAAK,EAAE;CAClF;CAEA,MAAa,mBACX,QACA,SACA,OACA,QACqC;;;GACrC,IAAI,WAAW,GACb,KAAK,OACH,QACA,qCAAqC,OAAO,cAAc,KAAK,UAAU,SAAS,cAAc,GAClG;GAGF,MAAM,EAAE,eAAe,KAAK,QAAQ,SAAS,MAAM;GACnD,MAAM,YAAY,cAAc,mBAAmB,SAAS,KAAK,MAAM,CAAC;GACxE,MAAM,EAAE,KAAK,UAAU,KAAK,QAAQ,kBAAkB;IACpD,cAAc;IACd,KAAK;IACL;GACF,CAAC;GACD,MAAM,aAAA,WAAA,EAAa,IAAI,eAAe,KAAK,CAAA;GAC3C,MAAM,YAAY,IAAI;GACtB,MAAM,EAAE,eAAe,kBAAkB,WAAW;GACpD,MAAM,SAAS,MAAM;GAErB,MAAM,iBAAiB,YAAY,IAAI,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;GAIjF,MAAM,EAAE,MAAM,gBAAgB,MAAM,KAAK,wBAAwB,IAAI,YAAY;IAU/E,OAAO;KAAE,MAAA,MANU,OAAO,QAAQ,CAAC,GAAG,UAAU,KAAK,CAAC,GAAG;MACvD;MACA,QAAQ;KACV,CAAC;KAGc,aAAA,MADW,WAAW,SAAS;IACnB;GAC7B,GAAG,cAAc;GAEjB,KAAK,oBAAoB,MAAM,WAAW,KAAK,GAAG,WAAW;GAC7D,OAAO,UAAU,KAAK,MAAM,OAAO;IAC3B;IACN,MAAM,KAAK;GACb,EAAE;;;;;;CACJ;CAEA,MAAa,gBACX,QACA,SACA,QAC+B;EAC/B,IAAI,WAAW,GACb,KAAK,OACH,QACA,kCAAkC,OAAO,cAAc,KAAK,UAAU,SAAS,cAAc,GAC/F;EAGF,MAAM,EAAE,mBAAmB,aAAa,kBAAkB,KAAK,QAAQ,SAAS,MAAM;EACtF,MAAM,aAAa,MAAM;EAEzB,MAAM,aAAa,YAAY,QAAQ;EACvC,IAAI,CAAC,YAAY;GACf,MAAM,QAAQ,IAAI,kBAAkB,wBAAwB;GAC5D,MAAM,wBAAQ,IAAI,MAAM,UAAU,QAAQ,SAAS,iCAAiC;GACpF,MAAM;EACR;EAEA,MAAM,UAAU,WAAW,WAAW,QAAQ;EAC9C,MAAM,YAAgC,CACpC,GAAG,WAAW,SAAS,KACpB,UAAU,OAAyB;GAClC,MAAM;GACN,IAAI,QAAQ;GACZ,MAAM;EACR,EACF,GACA;GAAE,MAAM;GAAU,IAAI,QAAQ;GAAU,MAAM;EAAW,CAC3D;EAEA,IAAI;EACJ,IAAI,QAAQ,SAAS,KAAA,GAAW;GAC9B,MAAM,QAAQ,gBAAgB,WAAW;IAAE,MAAM;IAAQ,IAAI,QAAQ;GAAK,CAAC;GAC3E,IAAI,QAAQ,GAAG;IACb,MAAM,QAAQ,IAAI,kBAAkB,wBAAwB;IAC5D,MAAM,wBAAQ,IAAI,MAChB,QAAQ,KAAK,UAAU,QAAQ,IAAI,EAAE,kCAAkC,QAAQ,UACjF;IACA,MAAM;GACR;GACA,YAAY;EACd;EAEA,MAAM,kBAAwD;GAC5D,UAAU,QAAQ;GAClB;GACA,SAAS,qBAAqB;IAC5B;IACA,SAAS,eAAe,QAAQ,SAAS,KAAK,MAAM;GACtD,CAAC;GACD,OAAO,QAAQ;EACjB;EAEA,MAAM,iBAAiB,YAAY,IAAI,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;EACjF,OAAO,MAAM,KAAK,wBAAwB,IAAI,YAAY;GACxD,OAAO,MAAM,WAAW,gBAAgB,iBAAiB,EAAE,QAAQ,eAAe,CAAC;EACrF,GAAG,cAAc;CACnB;CAMA,MAAa,QAAQ,QAAmD;EACtE,MAAM,EAAE,QAAQ,KAAK,WAAW,SAAS,MAAM;EAC/C,OAAO,IAAI;CACb;CAEA,MAAa,SAAS,QAAsB,QAA4C;;;GACtF,MAAM,EAAE,KAAK,eAAe,qBAAqB,KAAK,WAAW,SAAS,MAAM;GAChF,MAAM,aAAA,WAAA,EAAa,IAAI,eAAe,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAA;GAE/D,MAAM,EAAE,eAAe,kBAAkB,WAAW;GACpD,MAAM,SAAS,MAAM;GAErB,MAAM,iBAAiB,YAAY,IAAI,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;GACjF,MAAM,EAAE,OAAO,gBAAgB,MAAM,KAAK,wBAAwB,IAAI,YAAY;IAOhF,OAAO;KAAE,OAAA,MANW,OAAO,SAAS,EAClC,QAAQ,eACV,CAAC;KAIe,aAAA,MAFU,WAAW,SAAS;IAElB;GAC9B,GAAG,cAAc;GAEjB,KAAK,iBAAiB,MAAM,WAAW,KAAK,GAAG,aAAa,gBAAgB;GAC5E,OAAO;;;;;;CACT;CAEA,MAAa,QACX,QACA,eACA,OACA,QACyB;;;GACzB,MAAM,EAAE,KAAK,eAAe,qBAAqB,KAAK,WAAW,SAAS,MAAM;GAChF,MAAM,aAAA,WAAA,EAAa,IAAI,eAAe,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAA;GAE/D,MAAM,EAAE,eAAe,kBAAkB,WAAW;GACpD,MAAM,SAAS,MAAM;GAErB,MAAM,iBAAiB,YAAY,IAAI,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;GACjF,MAAM,EAAE,MAAM,gBAAgB,MAAM,KAAK,wBAAwB,IAAI,YAAY;IAQ/E,OAAO;KAAE,MAAA,MAPU,OAAO,QAAQ,eAAe;MAC/C;MACA,QAAQ;KACV,CAAC;KAIc,aAAA,MAFW,WAAW,SAAS;IAEnB;GAC7B,GAAG,cAAc;GAEjB,KAAK,iBAAiB,MAAM,WAAW,KAAK,GAAG,aAAa,gBAAgB;GAC5E,OAAO;;;;;;CACT;AACF;;AAGA,SAAS,UAAU,OAA+B,OAAgC;CAChF,IAAI,MAAM,KAAK,GACb,OAAO;EAAE,QAAQ;EAAG,QAAQ,MAAM;CAAK;CAEzC,MAAM,gBAAgB,KAAK,IAAI,MAAM,QAAQ,MAAM,IAAI;CAEvD,OAAO;EAAE,QAAQ;EAAe,QADV,KAAK,IAAI,MAAM,QAAQ,MAAM,OAAO,aACN;CAAE;AACxD;AAEA,SAAS,eACP,SACA,QACsB;CACtB,MAAM,YAAY,CAAC;CACnB,MAAM,YAA+C,CAAC;CACtD,KAAK,MAAM,UAAU,SACnB,IAAK,OAAO,SAAqB,kBAAkB;EACjD,UAAU,KAAK,MAAM;EACrB,UAAU,KAAK;GACb,GAAG;GACH,MAAM;EACR,CAAC;CACH,OACE,UAAU,KAAK,MAAM;CAGzB,IAAI,UAAU,SAAS,GAErB,OACE,QACA,6EAHoB,KAAK,UAAU,SAGsD,GAC3F;CAEF,OAAO;AACT;AAEA,SAAS,mBACP,KACA,QACc;CACd,IAAI,EAAE,sBAAsB,MAE1B,OAAO;EACL,GAAG;EACH,kBAAkB,eAChB,IAAI,QAAQ,QAAQ,MAAM,EAAE,OAAO,SAAS,MAAM,GAClD,MACF;EACA,SAAS,eACP,IAAI,QAAQ,QAAQ,MAAM,EAAE,OAAO,SAAS,QAAQ,GACpD,MACF;CACF;CAEF,OAAO;EACL,GAAG;EACH,kBAAkB,eAAe,IAAI,kBAAkB,MAAM;EAC7D,SAAS,eAAe,IAAI,SAAS,MAAM;CAC7C;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pf-driver",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.5",
|
|
4
4
|
"description": "PFrameDriver implementation abstracted from Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@milaboratories/pframes-rs-node": "1.1.
|
|
24
|
-
"@milaboratories/pframes-rs-wasm": "1.1.
|
|
23
|
+
"@milaboratories/pframes-rs-node": "1.1.56",
|
|
24
|
+
"@milaboratories/pframes-rs-wasm": "1.1.56",
|
|
25
25
|
"es-toolkit": "^1.39.10",
|
|
26
26
|
"lru-cache": "^11.2.2",
|
|
27
27
|
"@milaboratories/helpers": "1.14.5",
|
|
28
|
-
"@milaboratories/pl-model-common": "1.47.
|
|
29
|
-
"@milaboratories/
|
|
30
|
-
"@milaboratories/
|
|
28
|
+
"@milaboratories/pl-model-common": "1.47.3",
|
|
29
|
+
"@milaboratories/pl-model-middle-layer": "1.30.15",
|
|
30
|
+
"@milaboratories/ts-helpers": "1.8.6"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "~24.5.2",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"fast-csv": "5.0.5",
|
|
36
36
|
"typescript": "~5.9.3",
|
|
37
37
|
"vitest": "^4.1.3",
|
|
38
|
-
"@milaboratories/ts-configs": "1.3.1",
|
|
39
38
|
"@milaboratories/build-configs": "2.0.0",
|
|
39
|
+
"@milaboratories/ts-configs": "1.3.1",
|
|
40
40
|
"@milaboratories/ts-builder": "1.6.1"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
@@ -124,6 +124,26 @@ describe("formatRow", () => {
|
|
|
124
124
|
// ── streamPTableRows ─────────────────────────────────────────────────
|
|
125
125
|
|
|
126
126
|
describe("streamPTableRows", () => {
|
|
127
|
+
it("throws when headerNames length differs from columnIndices", async () => {
|
|
128
|
+
const specs = [makeAxisSpec("id", "ID"), makeColumnSpec("v", "Value")];
|
|
129
|
+
const pTable = makeMockPTable([]);
|
|
130
|
+
await expect(
|
|
131
|
+
collectStream(
|
|
132
|
+
streamPTableRows({
|
|
133
|
+
pTable,
|
|
134
|
+
columnIndices: [0, 1],
|
|
135
|
+
headerNames: ["only one"],
|
|
136
|
+
range: undefined,
|
|
137
|
+
chunkSize: 100,
|
|
138
|
+
separator: ",",
|
|
139
|
+
specs,
|
|
140
|
+
includeHeader: true,
|
|
141
|
+
bom: false,
|
|
142
|
+
}),
|
|
143
|
+
),
|
|
144
|
+
).rejects.toThrow(/headerNames length/);
|
|
145
|
+
});
|
|
146
|
+
|
|
127
147
|
it("emits BOM when requested", async () => {
|
|
128
148
|
const pTable = makeMockPTable([]);
|
|
129
149
|
const result = await collectStream(
|
package/src/csv_writer.ts
CHANGED
|
@@ -21,7 +21,9 @@ export interface PTableDataSource {
|
|
|
21
21
|
|
|
22
22
|
/** Format a CSV/TSV header row from column specs. Line ending is CRLF. */
|
|
23
23
|
export function formatHeader(specs: PTableColumnSpec[], separator: string): string {
|
|
24
|
-
return
|
|
24
|
+
return (
|
|
25
|
+
specs.map((spec) => escapeField(getNativeColumnLabel(spec), separator)).join(separator) + "\r\n"
|
|
26
|
+
);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
/** Format a single data row from parallel vectors. Line ending is CRLF. */
|
|
@@ -44,6 +46,13 @@ export interface StreamPTableRowsOptions {
|
|
|
44
46
|
pTable: PTableDataSource;
|
|
45
47
|
specs: PTableColumnSpec[];
|
|
46
48
|
columnIndices: number[];
|
|
49
|
+
/**
|
|
50
|
+
* Header names aligned 1:1 with `columnIndices`. When provided they are
|
|
51
|
+
* written verbatim, letting callers supply disambiguated labels the spec's
|
|
52
|
+
* intrinsic `pl7.app/label` may not carry. When omitted the header is derived
|
|
53
|
+
* from `specs` via {@link getNativeColumnLabel}.
|
|
54
|
+
*/
|
|
55
|
+
headerNames?: string[];
|
|
47
56
|
range?: TableRange;
|
|
48
57
|
chunkSize: number;
|
|
49
58
|
separator: string;
|
|
@@ -52,16 +61,27 @@ export interface StreamPTableRowsOptions {
|
|
|
52
61
|
signal?: AbortSignal;
|
|
53
62
|
}
|
|
54
63
|
export async function* streamPTableRows(options: StreamPTableRowsOptions): AsyncIterable<string> {
|
|
55
|
-
const { pTable, columnIndices, range, chunkSize, separator, signal, specs
|
|
64
|
+
const { pTable, columnIndices, headerNames, range, chunkSize, separator, signal, specs } =
|
|
56
65
|
options;
|
|
66
|
+
const { includeHeader, bom } = options;
|
|
67
|
+
|
|
68
|
+
if (headerNames !== undefined && headerNames.length !== columnIndices.length) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`headerNames length (${headerNames.length}) must match columnIndices length (${columnIndices.length})`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
57
73
|
|
|
58
74
|
if (bom) {
|
|
59
75
|
yield "\uFEFF";
|
|
60
76
|
}
|
|
61
77
|
|
|
62
78
|
if (includeHeader) {
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
yield headerNames !== undefined
|
|
80
|
+
? headerNames.map((name) => escapeField(name, separator)).join(separator) + "\r\n"
|
|
81
|
+
: formatHeader(
|
|
82
|
+
columnIndices.map((index) => specs[index]),
|
|
83
|
+
separator,
|
|
84
|
+
);
|
|
65
85
|
}
|
|
66
86
|
|
|
67
87
|
if (isNil(range)) {
|
|
@@ -89,7 +109,7 @@ export async function* streamPTableRows(options: StreamPTableRowsOptions): Async
|
|
|
89
109
|
// ── Helpers (low-level) ──────────────────────────────────────────────
|
|
90
110
|
|
|
91
111
|
/** Extract a human-readable label from a PTableColumnSpec. */
|
|
92
|
-
export function
|
|
112
|
+
export function getNativeColumnLabel(spec: PTableColumnSpec): string {
|
|
93
113
|
const annotation = readAnnotation(spec.spec, Annotation.Label);
|
|
94
114
|
return isNil(annotation) ? spec.spec.name : annotation.trim();
|
|
95
115
|
}
|
package/src/driver_decl.ts
CHANGED
|
@@ -105,8 +105,9 @@ export interface AbstractInternalPFrameDriver<PColumnData> extends PFrameDriver,
|
|
|
105
105
|
/**
|
|
106
106
|
* Export the table to a file, selecting the format from the extension of
|
|
107
107
|
* `options.path` (`csv`/`tsv`/`parquet`/`xlsx`). `options.columnIndices`
|
|
108
|
-
* selects the columns to export (output order);
|
|
109
|
-
*
|
|
108
|
+
* selects the columns to export (output order); optional
|
|
109
|
+
* `options.headerNames` (aligned 1:1) names them, with a missing or empty
|
|
110
|
+
* entry falling back to the field's label annotation (then the spec name).
|
|
110
111
|
*/
|
|
111
112
|
exportPTable(
|
|
112
113
|
handle: PTableHandle,
|
|
@@ -527,7 +527,11 @@ test("exportPTable writes a CSV with derived headers", async ({ expect }) => {
|
|
|
527
527
|
try {
|
|
528
528
|
const filePath = join(tempDir, "table.csv");
|
|
529
529
|
|
|
530
|
-
|
|
530
|
+
// Omitted headerNames fall back to labels derived from the column/axis specs.
|
|
531
|
+
await uiDriver.exportPTable(pTable.key, {
|
|
532
|
+
path: filePath,
|
|
533
|
+
columnIndices: [0, 1],
|
|
534
|
+
});
|
|
531
535
|
|
|
532
536
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
533
537
|
const lines = content.split(/\r?\n/).filter((l) => l.length > 0);
|
|
@@ -540,3 +544,109 @@ test("exportPTable writes a CSV with derived headers", async ({ expect }) => {
|
|
|
540
544
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
541
545
|
}
|
|
542
546
|
});
|
|
547
|
+
|
|
548
|
+
test("exportPTable writes caller-supplied header names verbatim", async ({ expect }) => {
|
|
549
|
+
await using driver = await createPFrameDriverDouble({});
|
|
550
|
+
|
|
551
|
+
const columnId = "column1" as PObjectId;
|
|
552
|
+
const column = {
|
|
553
|
+
id: columnId,
|
|
554
|
+
spec: {
|
|
555
|
+
kind: "PColumn" as const,
|
|
556
|
+
axesSpec: [
|
|
557
|
+
{
|
|
558
|
+
name: "axis1",
|
|
559
|
+
type: "String" as const,
|
|
560
|
+
annotations: { "pl7.app/label": "Sample" },
|
|
561
|
+
},
|
|
562
|
+
],
|
|
563
|
+
name: "column1",
|
|
564
|
+
valueType: "Int" as const,
|
|
565
|
+
annotations: { "pl7.app/label": "Score" },
|
|
566
|
+
},
|
|
567
|
+
data: [
|
|
568
|
+
{ key: ["a"], val: 10 },
|
|
569
|
+
{ key: ["b"], val: 20 },
|
|
570
|
+
{ key: ["c"], val: 30 },
|
|
571
|
+
],
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const uiDriver: PFrameDriver = driver;
|
|
575
|
+
|
|
576
|
+
using pTable = driver.createPTableV2({ query: { type: "column", column } });
|
|
577
|
+
|
|
578
|
+
const tempDir = fs.mkdtempSync(join(os.tmpdir(), "pf-export-"));
|
|
579
|
+
try {
|
|
580
|
+
const filePath = join(tempDir, "table.csv");
|
|
581
|
+
|
|
582
|
+
// Caller-supplied names (the disambiguated labels the UI shows) win over the
|
|
583
|
+
// spec's intrinsic `pl7.app/label`.
|
|
584
|
+
await uiDriver.exportPTable(pTable.key, {
|
|
585
|
+
path: filePath,
|
|
586
|
+
columnIndices: [0, 1],
|
|
587
|
+
headerNames: ["Sample id", "Score (disambiguated)"],
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
591
|
+
const lines = content.split(/\r?\n/).filter((l) => l.length > 0);
|
|
592
|
+
|
|
593
|
+
expect(lines[0]).toBe("Sample id,Score (disambiguated)");
|
|
594
|
+
expect(lines.slice(1)).toEqual(["a,10", "b,20", "c,30"]);
|
|
595
|
+
} finally {
|
|
596
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
test("writePTableToFs writes caller-supplied header names verbatim", async ({ expect }) => {
|
|
601
|
+
await using driver = await createPFrameDriverDouble({});
|
|
602
|
+
|
|
603
|
+
const columnId = "column1" as PObjectId;
|
|
604
|
+
const column = {
|
|
605
|
+
id: columnId,
|
|
606
|
+
spec: {
|
|
607
|
+
kind: "PColumn" as const,
|
|
608
|
+
axesSpec: [
|
|
609
|
+
{
|
|
610
|
+
name: "axis1",
|
|
611
|
+
type: "String" as const,
|
|
612
|
+
annotations: { "pl7.app/label": "Sample" },
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
name: "column1",
|
|
616
|
+
valueType: "Int" as const,
|
|
617
|
+
annotations: { "pl7.app/label": "Score" },
|
|
618
|
+
},
|
|
619
|
+
data: [
|
|
620
|
+
{ key: ["a"], val: 10 },
|
|
621
|
+
{ key: ["b"], val: 20 },
|
|
622
|
+
{ key: ["c"], val: 30 },
|
|
623
|
+
],
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const uiDriver: PFrameDriver = driver;
|
|
627
|
+
|
|
628
|
+
using pTable = driver.createPTableV2({ query: { type: "column", column } });
|
|
629
|
+
|
|
630
|
+
const tempDir = fs.mkdtempSync(join(os.tmpdir(), "pf-export-"));
|
|
631
|
+
try {
|
|
632
|
+
const filePath = join(tempDir, "table.csv");
|
|
633
|
+
|
|
634
|
+
// Fallback path (writePTableToFs): caller-supplied names win over the spec
|
|
635
|
+
// labels, mirroring the native exportPTable path.
|
|
636
|
+
await uiDriver.writePTableToFs(pTable.key, {
|
|
637
|
+
path: filePath,
|
|
638
|
+
format: "csv",
|
|
639
|
+
columnIndices: [0, 1],
|
|
640
|
+
headerNames: ["Sample id", "Score (disambiguated)"],
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// Strip the leading BOM the CSV writer emits by default.
|
|
644
|
+
const content = fs.readFileSync(filePath, "utf-8").replace(/^/, "");
|
|
645
|
+
const lines = content.split(/\r?\n/).filter((l) => l.length > 0);
|
|
646
|
+
|
|
647
|
+
expect(lines[0]).toBe("Sample id,Score (disambiguated)");
|
|
648
|
+
expect(lines.slice(1)).toEqual(["a,10", "b,20", "c,30"]);
|
|
649
|
+
} finally {
|
|
650
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
651
|
+
}
|
|
652
|
+
});
|
package/src/driver_impl.ts
CHANGED
|
@@ -50,7 +50,7 @@ import * as fs from "node:fs";
|
|
|
50
50
|
import { Readable } from "node:stream";
|
|
51
51
|
import { pipeline } from "node:stream/promises";
|
|
52
52
|
import * as zlib from "node:zlib";
|
|
53
|
-
import {
|
|
53
|
+
import { getNativeColumnLabel, streamPTableRows } from "./csv_writer";
|
|
54
54
|
import type {
|
|
55
55
|
AbstractInternalPFrameDriver,
|
|
56
56
|
WritePTableToFsOptions,
|
|
@@ -297,6 +297,14 @@ export class AbstractPFrameDriver<
|
|
|
297
297
|
const { pTablePromise, disposeSignal } = tableGuard.resource;
|
|
298
298
|
const pTable = await pTablePromise;
|
|
299
299
|
|
|
300
|
+
// Caller-supplied header names win (they carry the disambiguated labels the
|
|
301
|
+
// UI shows); a missing or empty name falls back to the spec-derived label.
|
|
302
|
+
const { columnIndices } = options;
|
|
303
|
+
const headerNames = columnIndices.map((index, i) => {
|
|
304
|
+
const name = options.headerNames?.[i];
|
|
305
|
+
return name !== undefined && name !== "" ? name : getNativeColumnLabel(def.tableSpec[index]);
|
|
306
|
+
});
|
|
307
|
+
|
|
300
308
|
const combinedSignal = AbortSignal.any(
|
|
301
309
|
[options.signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),
|
|
302
310
|
);
|
|
@@ -316,7 +324,8 @@ export class AbstractPFrameDriver<
|
|
|
316
324
|
const iterable = streamPTableRows({
|
|
317
325
|
pTable,
|
|
318
326
|
specs,
|
|
319
|
-
columnIndices
|
|
327
|
+
columnIndices,
|
|
328
|
+
headerNames,
|
|
320
329
|
range: clippedRange,
|
|
321
330
|
chunkSize: options.chunkSize ?? 50_000,
|
|
322
331
|
separator,
|
|
@@ -354,7 +363,7 @@ export class AbstractPFrameDriver<
|
|
|
354
363
|
const durationMs = Math.round(performance.now() - startTime);
|
|
355
364
|
this.logger(
|
|
356
365
|
"info",
|
|
357
|
-
`[WritePTableToFs] complete (handle = ${handle}, columns = ${
|
|
366
|
+
`[WritePTableToFs] complete (handle = ${handle}, columns = ${columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,
|
|
358
367
|
);
|
|
359
368
|
}
|
|
360
369
|
|
|
@@ -384,10 +393,15 @@ export class AbstractPFrameDriver<
|
|
|
384
393
|
[signal, disposeSignal].filter((s): s is AbortSignal => !isNil(s)),
|
|
385
394
|
);
|
|
386
395
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
396
|
+
// Caller-supplied header names win (they carry the disambiguated labels the
|
|
397
|
+
// UI shows); a missing or empty name falls back to the spec-derived label.
|
|
398
|
+
const headers: [number, string][] = columnIndices.map((index, i): [number, string] => {
|
|
399
|
+
const name = options.headerNames?.[i];
|
|
400
|
+
return [
|
|
401
|
+
index,
|
|
402
|
+
name !== undefined && name !== "" ? name : getNativeColumnLabel(def.tableSpec[index]),
|
|
403
|
+
];
|
|
404
|
+
});
|
|
391
405
|
|
|
392
406
|
// keep()/cache live outside the limiter task: on abort `run` rejects and they are
|
|
393
407
|
// skipped, so an abandoned (detached) operation never caches its result nor touches
|