@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.
@@ -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(columnLabel(spec), separator)).join(separator) + "\r\n";
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, includeHeader, bom } = options;
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 columnLabel(spec) {
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
@@ -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(columnLabel(spec), separator)).join(separator) + \"\\r\\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 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, range, chunkSize, separator, signal, specs, includeHeader, bom } =\n options;\n\n if (bom) {\n yield \"\\uFEFF\";\n }\n\n if (includeHeader) {\n const selectedSpecs = columnIndices.map((index) => specs[index]);\n yield formatHeader(selectedSpecs, separator);\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 columnLabel(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,OAAO,MAAM,KAAK,SAAS,YAAY,YAAY,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI;AAC1F;;AAGA,SAAgB,UAAU,SAAyB,UAAkB,WAA2B;CAC9F,OACE,QACG,KAAK,WAAW,YAAY,eAAe,QAAQ,QAAQ,GAAG,SAAS,CAAC,CAAC,CACzE,KAAK,SAAS,IAAI;AAEzB;AAoBA,gBAAuB,iBAAiB,SAAyD;CAC/F,MAAM,EAAE,QAAQ,eAAe,OAAO,WAAW,WAAW,QAAQ,OAAO,eAAe,QACxF;CAEF,IAAI,KACF,MAAM;CAGR,IAAI,eAEF,MAAM,aADgB,cAAc,KAAK,UAAU,MAAM,MAC1B,GAAG,SAAS;CAG7C,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,YAAY,MAAgC;CAC1D,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"}
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"}
@@ -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(columnLabel(spec), separator)).join(separator) + "\r\n";
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, includeHeader, bom } = options;
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 columnLabel(spec) {
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 { columnLabel, formatHeader, formatRow, streamPTableRows };
78
+ export { formatHeader, formatRow, getNativeColumnLabel, streamPTableRows };
77
79
 
78
80
  //# sourceMappingURL=csv_writer.js.map
@@ -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(columnLabel(spec), separator)).join(separator) + \"\\r\\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 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, range, chunkSize, separator, signal, specs, includeHeader, bom } =\n options;\n\n if (bom) {\n yield \"\\uFEFF\";\n }\n\n if (includeHeader) {\n const selectedSpecs = columnIndices.map((index) => specs[index]);\n yield formatHeader(selectedSpecs, separator);\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 columnLabel(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,OAAO,MAAM,KAAK,SAAS,YAAY,YAAY,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI;AAC1F;;AAGA,SAAgB,UAAU,SAAyB,UAAkB,WAA2B;CAC9F,OACE,QACG,KAAK,WAAW,YAAY,eAAe,QAAQ,QAAQ,GAAG,SAAS,CAAC,CAAC,CACzE,KAAK,SAAS,IAAI;AAEzB;AAoBA,gBAAuB,iBAAiB,SAAyD;CAC/F,MAAM,EAAE,QAAQ,eAAe,OAAO,WAAW,WAAW,QAAQ,OAAO,eAAe,QACxF;CAEF,IAAI,KACF,MAAM;CAGR,IAAI,eAEF,MAAM,aADgB,cAAc,KAAK,UAAU,MAAM,MAC1B,GAAG,SAAS;CAG7C,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,YAAY,MAAgC;CAC1D,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"}
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"}
@@ -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); headers are derived from
55
- * each field's label annotation (falling back to the spec name).
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;;;;;;EAcH,YAAA,CACE,MAAA,EAAQ,YAAA,EACR,OAAA,EAAS,mBAAA,EACT,MAAA,GAAS,WAAA,GACR,OAAA;AAAA"}
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"}
@@ -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: options.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 = ${options.columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`);
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) => [index, require_csv_writer.columnLabel(def.tableSpec[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 });
@@ -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":"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"}
1
+ {"version":3,"file":"driver_impl.d.ts","names":[],"sources":["../src/driver_impl.ts"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { columnLabel, streamPTableRows } from "./csv_writer.js";
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: options.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 = ${options.columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`);
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) => [index, columnLabel(def.tableSpec[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 });
@@ -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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pf-driver",
3
- "version": "1.8.3",
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.55",
24
- "@milaboratories/pframes-rs-wasm": "1.1.55",
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.2",
29
- "@milaboratories/ts-helpers": "1.8.6",
30
- "@milaboratories/pl-model-middle-layer": "1.30.14"
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 specs.map((spec) => escapeField(columnLabel(spec), separator)).join(separator) + "\r\n";
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, includeHeader, bom } =
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
- const selectedSpecs = columnIndices.map((index) => specs[index]);
64
- yield formatHeader(selectedSpecs, separator);
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 columnLabel(spec: PTableColumnSpec): string {
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
  }
@@ -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); headers are derived from
109
- * each field's label annotation (falling back to the spec name).
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
- await uiDriver.exportPTable(pTable.key, { path: filePath, columnIndices: [0, 1] });
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
+ });
@@ -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 { columnLabel, streamPTableRows } from "./csv_writer";
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: options.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 = ${options.columnIndices.length}, rows = ${rowsWritten}, bytes = ${bytesWritten}, duration = ${durationMs}ms)`,
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
- const headers: [number, string][] = columnIndices.map((index): [number, string] => [
388
- index,
389
- columnLabel(def.tableSpec[index]),
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