@platforma-sdk/model 1.80.13 → 1.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/columns/column.cjs +9 -6
- package/dist/columns/column.cjs.map +1 -1
- package/dist/columns/column.d.ts +5 -5
- package/dist/columns/column.d.ts.map +1 -1
- package/dist/columns/column.js +10 -7
- package/dist/columns/column.js.map +1 -1
- package/dist/columns/column_providers/index.cjs.map +1 -1
- package/dist/columns/column_providers/index.d.ts.map +1 -1
- package/dist/columns/column_providers/index.js.map +1 -1
- package/dist/columns/column_providers/providers.cjs +5 -5
- package/dist/columns/column_providers/providers.cjs.map +1 -1
- package/dist/columns/column_providers/providers.d.ts +8 -8
- package/dist/columns/column_providers/providers.d.ts.map +1 -1
- package/dist/columns/column_providers/providers.js +5 -5
- package/dist/columns/column_providers/providers.js.map +1 -1
- package/dist/columns/column_providers/types.d.ts +3 -3
- package/dist/columns/column_providers/types.d.ts.map +1 -1
- package/dist/columns/column_recipes/column_discovered_recipe.cjs +1 -1
- package/dist/columns/column_recipes/column_discovered_recipe.cjs.map +1 -1
- package/dist/columns/column_recipes/column_discovered_recipe.d.ts +1 -1
- package/dist/columns/column_recipes/column_discovered_recipe.js +1 -1
- package/dist/columns/column_recipes/column_discovered_recipe.js.map +1 -1
- package/dist/columns/column_recipes/column_overrided_recipe.cjs +47 -2
- package/dist/columns/column_recipes/column_overrided_recipe.cjs.map +1 -1
- package/dist/columns/column_recipes/column_overrided_recipe.d.ts +30 -3
- package/dist/columns/column_recipes/column_overrided_recipe.d.ts.map +1 -1
- package/dist/columns/column_recipes/column_overrided_recipe.js +47 -3
- package/dist/columns/column_recipes/column_overrided_recipe.js.map +1 -1
- package/dist/columns/column_recipes/index.cjs +4 -14
- package/dist/columns/column_recipes/index.cjs.map +1 -1
- package/dist/columns/column_recipes/index.d.ts +3 -10
- package/dist/columns/column_recipes/index.d.ts.map +1 -1
- package/dist/columns/column_recipes/index.js +5 -14
- package/dist/columns/column_recipes/index.js.map +1 -1
- package/dist/columns/{column_lazy.cjs → data_column.cjs} +57 -54
- package/dist/columns/data_column.cjs.map +1 -0
- package/dist/columns/data_column.d.ts +152 -0
- package/dist/columns/data_column.d.ts.map +1 -0
- package/dist/columns/{column_lazy.js → data_column.js} +55 -52
- package/dist/columns/data_column.js.map +1 -0
- package/dist/columns/derive_axis_values_labels.cjs +4 -4
- package/dist/columns/derive_axis_values_labels.cjs.map +1 -1
- package/dist/columns/derive_axis_values_labels.d.ts +2 -2
- package/dist/columns/derive_axis_values_labels.js +4 -4
- package/dist/columns/derive_axis_values_labels.js.map +1 -1
- package/dist/columns/index.cjs +9 -9
- package/dist/columns/index.d.ts +5 -5
- package/dist/columns/index.js +5 -5
- package/dist/columns/{expand_by_partition.cjs → split_by_axes.cjs} +13 -8
- package/dist/columns/split_by_axes.cjs.map +1 -0
- package/dist/columns/{expand_by_partition.d.ts → split_by_axes.d.ts} +18 -8
- package/dist/columns/split_by_axes.d.ts.map +1 -0
- package/dist/columns/{expand_by_partition.js → split_by_axes.js} +14 -9
- package/dist/columns/split_by_axes.js.map +1 -0
- package/dist/columns/utils.cjs +50 -43
- package/dist/columns/utils.cjs.map +1 -1
- package/dist/columns/utils.d.ts +44 -19
- package/dist/columns/utils.d.ts.map +1 -1
- package/dist/columns/utils.js +50 -44
- package/dist/columns/utils.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs +3 -3
- package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js +3 -3
- package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +2 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +2 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +2 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +1 -1
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +2 -2
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
- package/dist/components/PlDatasetSelector/enrichment_discovery.cjs +1 -1
- package/dist/components/PlDatasetSelector/enrichment_discovery.cjs.map +1 -1
- package/dist/components/PlDatasetSelector/enrichment_discovery.js +2 -2
- package/dist/components/PlDatasetSelector/enrichment_discovery.js.map +1 -1
- package/dist/index.cjs +9 -9
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -5
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/package.json +9 -9
- package/src/columns/__test_helpers__/collection_driver.ts +6 -6
- package/src/columns/__test_helpers__/stub_registry.ts +4 -6
- package/src/columns/column.ts +20 -9
- package/src/columns/column_providers/index.ts +9 -3
- package/src/columns/column_providers/providers.ts +16 -15
- package/src/columns/column_providers/types.ts +3 -3
- package/src/columns/column_recipes/column_discovered_recipe.ts +1 -1
- package/src/columns/column_recipes/column_overrided_recipe.ts +58 -4
- package/src/columns/column_recipes/column_recipes.test.ts +2 -2
- package/src/columns/column_recipes/index.ts +5 -20
- package/src/columns/{column_lazy.test.ts → data_column.test.ts} +19 -19
- package/src/columns/{column_lazy.ts → data_column.ts} +105 -67
- package/src/columns/derive_axis_values_labels.ts +4 -4
- package/src/columns/index.ts +2 -2
- package/src/columns/predicates.test.ts +124 -0
- package/src/columns/{expand_by_partition.test.ts → split_by_axes.test.ts} +29 -21
- package/src/columns/{expand_by_partition.ts → split_by_axes.ts} +22 -9
- package/src/columns/utils.ts +53 -48
- package/src/components/PlDataTable/columnResolver.test.ts +3 -3
- package/src/components/PlDataTable/createPlDataTable/createPTableDefV2.ts +3 -3
- package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +2 -2
- package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +2 -2
- package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +2 -2
- package/src/components/PlDataTable/createPlDataTable/utils.test.ts +3 -3
- package/src/components/PlDatasetSelector/enrichment_discovery.ts +2 -2
- package/dist/columns/column_lazy.cjs.map +0 -1
- package/dist/columns/column_lazy.d.ts +0 -137
- package/dist/columns/column_lazy.d.ts.map +0 -1
- package/dist/columns/column_lazy.js.map +0 -1
- package/dist/columns/expand_by_partition.cjs.map +0 -1
- package/dist/columns/expand_by_partition.d.ts.map +0 -1
- package/dist/columns/expand_by_partition.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const require_accessor = require("../render/accessor.cjs");
|
|
2
2
|
require("../render/index.cjs");
|
|
3
|
-
const require_column_lazy = require("./column_lazy.cjs");
|
|
4
3
|
const require_columns_collection = require("./columns_collection.cjs");
|
|
4
|
+
const require_utils = require("./utils.cjs");
|
|
5
5
|
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
6
6
|
//#region src/columns/derive_axis_values_labels.ts
|
|
7
7
|
const RT_JSON = "PColumnData/Json";
|
|
@@ -15,11 +15,11 @@ const RT_JSON_PARTITIONED = "PColumnData/JsonPartitioned";
|
|
|
15
15
|
* column-access mechanism (filtered {@link ColumnsCollection}) instead of
|
|
16
16
|
* walking the raw result pool.
|
|
17
17
|
*
|
|
18
|
-
* Pair with {@link
|
|
18
|
+
* Pair with {@link splitByAxes} (or any consumer expecting the
|
|
19
19
|
* `(axisId) => Record<axisValue, label>` shape).
|
|
20
20
|
*
|
|
21
21
|
* Skips:
|
|
22
|
-
* -
|
|
22
|
+
* - recipes whose data is not directly readable (see `hasReachableData`);
|
|
23
23
|
* - label columns whose `axesSpec.length !== 1`;
|
|
24
24
|
* - label columns whose data resource type isn't `PColumnData/Json` /
|
|
25
25
|
* `PColumnData/JsonPartitioned`.
|
|
@@ -29,7 +29,7 @@ function deriveAxisValuesLabels(source, opts) {
|
|
|
29
29
|
type: "exact",
|
|
30
30
|
value: _milaboratories_pl_model_common.PColumnName.Label
|
|
31
31
|
}] } }).getColumns().reduce((map, col) => {
|
|
32
|
-
if (!
|
|
32
|
+
if (!require_utils.hasReachableData(col)) return map;
|
|
33
33
|
const spec = col.getSpec();
|
|
34
34
|
if (spec.axesSpec.length !== 1) return map;
|
|
35
35
|
const data = col.getData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive_axis_values_labels.cjs","names":["ColumnsCollection","isColumnsCollection","PColumnName","
|
|
1
|
+
{"version":3,"file":"derive_axis_values_labels.cjs","names":["ColumnsCollection","isColumnsCollection","PColumnName","hasReachableData","TreeNodeAccessor"],"sources":["../../src/columns/derive_axis_values_labels.ts"],"sourcesContent":["import type { AxisId } from \"@milaboratories/pl-model-common\";\nimport { canonicalizeAxisId, getAxisId, PColumnName } from \"@milaboratories/pl-model-common\";\nimport type { ColumnsSource } from \"./column_providers\";\nimport { ColumnsCollection, isColumnsCollection } from \"./columns_collection\";\nimport type { GlobalCfgRenderCtx } from \"../render/internal\";\nimport { TreeNodeAccessor } from \"../render\";\nimport { hasReachableData } from \"./utils\";\n\nconst RT_JSON = \"PColumnData/Json\";\nconst RT_JSON_PARTITIONED = \"PColumnData/JsonPartitioned\";\n\n/**\n * Build an `axisValuesLabels` callback by discovering `pl7.app/label` columns\n * from the given source, eagerly materialising their value→label maps, and\n * keying them by canonical axis id.\n *\n * Modern replacement for `ctx.resultPool.findLabels` — uses the new\n * column-access mechanism (filtered {@link ColumnsCollection}) instead of\n * walking the raw result pool.\n *\n * Pair with {@link splitByAxes} (or any consumer expecting the\n * `(axisId) => Record<axisValue, label>` shape).\n *\n * Skips:\n * - recipes whose data is not directly readable (see `hasReachableData`);\n * - label columns whose `axesSpec.length !== 1`;\n * - label columns whose data resource type isn't `PColumnData/Json` /\n * `PColumnData/JsonPartitioned`.\n */\nexport function deriveAxisValuesLabels(\n source?: ColumnsCollection | (ColumnsCollection | ColumnsSource)[],\n opts?: { ctx?: GlobalCfgRenderCtx },\n): (axisId: AxisId) => Record<string | number, string> | undefined {\n const collection =\n source === undefined\n ? ColumnsCollection(undefined, opts)\n : isColumnsCollection(source)\n ? source\n : ColumnsCollection(source, opts);\n\n const labelCols = collection\n .filter({ include: { name: [{ type: \"exact\", value: PColumnName.Label }] } })\n .getColumns();\n\n const byAxis = labelCols.reduce<Map<string, Record<string | number, string>>>((map, col) => {\n if (!hasReachableData(col)) return map;\n const spec = col.getSpec();\n if (spec.axesSpec.length !== 1) return map;\n\n const data = col.getData();\n if (!(data instanceof TreeNodeAccessor)) return map;\n\n const labelMap = readLabelMap(data);\n if (!labelMap) return map;\n\n map.set(canonicalizeAxisId(getAxisId(spec.axesSpec[0])), labelMap);\n return map;\n }, new Map());\n\n return (axisId) => byAxis.get(canonicalizeAxisId(axisId));\n}\n\nfunction readLabelMap(acc: TreeNodeAccessor): undefined | Record<string | number, string> {\n const rt = acc.resourceType.name;\n\n if (rt === RT_JSON) {\n const json = acc.getDataAsJson<{ data?: Record<string, string> }>();\n return json?.data ? parseLabelKeys(json.data) : undefined;\n }\n\n if (rt === RT_JSON_PARTITIONED) {\n return acc.listInputFields().reduce<Record<string | number, string>>((merged, partKey) => {\n const part = acc.resolve({\n field: partKey,\n assertFieldType: \"Input\",\n ignoreError: true,\n });\n if (!part) return merged;\n const json = part.getDataAsJson<{ data?: Record<string, string> }>();\n if (!json?.data) return merged;\n return Object.assign(merged, parseLabelKeys(json.data));\n }, {});\n }\n\n return undefined;\n}\n\nfunction parseLabelKeys(raw: Record<string, string>): Record<string | number, string> {\n return Object.entries(raw).reduce<Record<string | number, string>>((acc, [k, v]) => {\n try {\n const parsed = JSON.parse(k);\n acc[Array.isArray(parsed) ? parsed[0] : parsed] = v;\n } catch {\n acc[k] = v;\n }\n return acc;\n }, {});\n}\n"],"mappings":";;;;;;AAQA,MAAM,UAAU;AAChB,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;AAoB5B,SAAgB,uBACd,QACA,MACiE;CAYjE,MAAM,UAVJ,WAAW,KAAA,IACPA,2BAAAA,kBAAkB,KAAA,GAAW,IAAI,IACjCC,2BAAAA,oBAAoB,MAAM,IACxB,SACAD,2BAAAA,kBAAkB,QAAQ,IAAI,EAAA,CAGnC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;EAAE,MAAM;EAAS,OAAOE,gCAAAA,YAAY;CAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAC5E,WAEoB,CAAC,CAAC,QAAsD,KAAK,QAAQ;EAC1F,IAAI,CAACC,cAAAA,iBAAiB,GAAG,GAAG,OAAO;EACnC,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,KAAK,SAAS,WAAW,GAAG,OAAO;EAEvC,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,EAAE,gBAAgBC,iBAAAA,mBAAmB,OAAO;EAEhD,MAAM,WAAW,aAAa,IAAI;EAClC,IAAI,CAAC,UAAU,OAAO;EAEtB,IAAI,KAAA,GAAA,gCAAA,mBAAA,EAAA,GAAA,gCAAA,UAAA,CAAiC,KAAK,SAAS,EAAE,CAAC,GAAG,QAAQ;EACjE,OAAO;CACT,mBAAG,IAAI,IAAI,CAAC;CAEZ,QAAQ,WAAW,OAAO,KAAA,GAAA,gCAAA,mBAAA,CAAuB,MAAM,CAAC;AAC1D;AAEA,SAAS,aAAa,KAAoE;CACxF,MAAM,KAAK,IAAI,aAAa;CAE5B,IAAI,OAAO,SAAS;EAClB,MAAM,OAAO,IAAI,cAAiD;EAClE,OAAO,MAAM,OAAO,eAAe,KAAK,IAAI,IAAI,KAAA;CAClD;CAEA,IAAI,OAAO,qBACT,OAAO,IAAI,gBAAgB,CAAC,CAAC,QAAyC,QAAQ,YAAY;EACxF,MAAM,OAAO,IAAI,QAAQ;GACvB,OAAO;GACP,iBAAiB;GACjB,aAAa;EACf,CAAC;EACD,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,OAAO,KAAK,cAAiD;EACnE,IAAI,CAAC,MAAM,MAAM,OAAO;EACxB,OAAO,OAAO,OAAO,QAAQ,eAAe,KAAK,IAAI,CAAC;CACxD,GAAG,CAAC,CAAC;AAIT;AAEA,SAAS,eAAe,KAA8D;CACpF,OAAO,OAAO,QAAQ,GAAG,CAAC,CAAC,QAAyC,KAAK,CAAC,GAAG,OAAO;EAClF,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,CAAC;GAC3B,IAAI,MAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,UAAU;EACpD,QAAQ;GACN,IAAI,KAAK;EACX;EACA,OAAO;CACT,GAAG,CAAC,CAAC;AACP"}
|
|
@@ -13,11 +13,11 @@ import { AxisId } from "@milaboratories/pl-model-common";
|
|
|
13
13
|
* column-access mechanism (filtered {@link ColumnsCollection}) instead of
|
|
14
14
|
* walking the raw result pool.
|
|
15
15
|
*
|
|
16
|
-
* Pair with {@link
|
|
16
|
+
* Pair with {@link splitByAxes} (or any consumer expecting the
|
|
17
17
|
* `(axisId) => Record<axisValue, label>` shape).
|
|
18
18
|
*
|
|
19
19
|
* Skips:
|
|
20
|
-
* -
|
|
20
|
+
* - recipes whose data is not directly readable (see `hasReachableData`);
|
|
21
21
|
* - label columns whose `axesSpec.length !== 1`;
|
|
22
22
|
* - label columns whose data resource type isn't `PColumnData/Json` /
|
|
23
23
|
* `PColumnData/JsonPartitioned`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TreeNodeAccessor } from "../render/accessor.js";
|
|
2
2
|
import "../render/index.js";
|
|
3
|
-
import { isColumnLazy } from "./column_lazy.js";
|
|
4
3
|
import { ColumnsCollection, isColumnsCollection } from "./columns_collection.js";
|
|
4
|
+
import { hasReachableData } from "./utils.js";
|
|
5
5
|
import { PColumnName, canonicalizeAxisId, getAxisId } from "@milaboratories/pl-model-common";
|
|
6
6
|
//#region src/columns/derive_axis_values_labels.ts
|
|
7
7
|
const RT_JSON = "PColumnData/Json";
|
|
@@ -15,11 +15,11 @@ const RT_JSON_PARTITIONED = "PColumnData/JsonPartitioned";
|
|
|
15
15
|
* column-access mechanism (filtered {@link ColumnsCollection}) instead of
|
|
16
16
|
* walking the raw result pool.
|
|
17
17
|
*
|
|
18
|
-
* Pair with {@link
|
|
18
|
+
* Pair with {@link splitByAxes} (or any consumer expecting the
|
|
19
19
|
* `(axisId) => Record<axisValue, label>` shape).
|
|
20
20
|
*
|
|
21
21
|
* Skips:
|
|
22
|
-
* -
|
|
22
|
+
* - recipes whose data is not directly readable (see `hasReachableData`);
|
|
23
23
|
* - label columns whose `axesSpec.length !== 1`;
|
|
24
24
|
* - label columns whose data resource type isn't `PColumnData/Json` /
|
|
25
25
|
* `PColumnData/JsonPartitioned`.
|
|
@@ -29,7 +29,7 @@ function deriveAxisValuesLabels(source, opts) {
|
|
|
29
29
|
type: "exact",
|
|
30
30
|
value: PColumnName.Label
|
|
31
31
|
}] } }).getColumns().reduce((map, col) => {
|
|
32
|
-
if (!
|
|
32
|
+
if (!hasReachableData(col)) return map;
|
|
33
33
|
const spec = col.getSpec();
|
|
34
34
|
if (spec.axesSpec.length !== 1) return map;
|
|
35
35
|
const data = col.getData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive_axis_values_labels.js","names":[],"sources":["../../src/columns/derive_axis_values_labels.ts"],"sourcesContent":["import type { AxisId } from \"@milaboratories/pl-model-common\";\nimport { canonicalizeAxisId, getAxisId, PColumnName } from \"@milaboratories/pl-model-common\";\nimport type { ColumnsSource } from \"./column_providers\";\nimport { ColumnsCollection, isColumnsCollection } from \"./columns_collection\";\nimport type { GlobalCfgRenderCtx } from \"../render/internal\";\nimport { TreeNodeAccessor } from \"../render\";\nimport {
|
|
1
|
+
{"version":3,"file":"derive_axis_values_labels.js","names":[],"sources":["../../src/columns/derive_axis_values_labels.ts"],"sourcesContent":["import type { AxisId } from \"@milaboratories/pl-model-common\";\nimport { canonicalizeAxisId, getAxisId, PColumnName } from \"@milaboratories/pl-model-common\";\nimport type { ColumnsSource } from \"./column_providers\";\nimport { ColumnsCollection, isColumnsCollection } from \"./columns_collection\";\nimport type { GlobalCfgRenderCtx } from \"../render/internal\";\nimport { TreeNodeAccessor } from \"../render\";\nimport { hasReachableData } from \"./utils\";\n\nconst RT_JSON = \"PColumnData/Json\";\nconst RT_JSON_PARTITIONED = \"PColumnData/JsonPartitioned\";\n\n/**\n * Build an `axisValuesLabels` callback by discovering `pl7.app/label` columns\n * from the given source, eagerly materialising their value→label maps, and\n * keying them by canonical axis id.\n *\n * Modern replacement for `ctx.resultPool.findLabels` — uses the new\n * column-access mechanism (filtered {@link ColumnsCollection}) instead of\n * walking the raw result pool.\n *\n * Pair with {@link splitByAxes} (or any consumer expecting the\n * `(axisId) => Record<axisValue, label>` shape).\n *\n * Skips:\n * - recipes whose data is not directly readable (see `hasReachableData`);\n * - label columns whose `axesSpec.length !== 1`;\n * - label columns whose data resource type isn't `PColumnData/Json` /\n * `PColumnData/JsonPartitioned`.\n */\nexport function deriveAxisValuesLabels(\n source?: ColumnsCollection | (ColumnsCollection | ColumnsSource)[],\n opts?: { ctx?: GlobalCfgRenderCtx },\n): (axisId: AxisId) => Record<string | number, string> | undefined {\n const collection =\n source === undefined\n ? ColumnsCollection(undefined, opts)\n : isColumnsCollection(source)\n ? source\n : ColumnsCollection(source, opts);\n\n const labelCols = collection\n .filter({ include: { name: [{ type: \"exact\", value: PColumnName.Label }] } })\n .getColumns();\n\n const byAxis = labelCols.reduce<Map<string, Record<string | number, string>>>((map, col) => {\n if (!hasReachableData(col)) return map;\n const spec = col.getSpec();\n if (spec.axesSpec.length !== 1) return map;\n\n const data = col.getData();\n if (!(data instanceof TreeNodeAccessor)) return map;\n\n const labelMap = readLabelMap(data);\n if (!labelMap) return map;\n\n map.set(canonicalizeAxisId(getAxisId(spec.axesSpec[0])), labelMap);\n return map;\n }, new Map());\n\n return (axisId) => byAxis.get(canonicalizeAxisId(axisId));\n}\n\nfunction readLabelMap(acc: TreeNodeAccessor): undefined | Record<string | number, string> {\n const rt = acc.resourceType.name;\n\n if (rt === RT_JSON) {\n const json = acc.getDataAsJson<{ data?: Record<string, string> }>();\n return json?.data ? parseLabelKeys(json.data) : undefined;\n }\n\n if (rt === RT_JSON_PARTITIONED) {\n return acc.listInputFields().reduce<Record<string | number, string>>((merged, partKey) => {\n const part = acc.resolve({\n field: partKey,\n assertFieldType: \"Input\",\n ignoreError: true,\n });\n if (!part) return merged;\n const json = part.getDataAsJson<{ data?: Record<string, string> }>();\n if (!json?.data) return merged;\n return Object.assign(merged, parseLabelKeys(json.data));\n }, {});\n }\n\n return undefined;\n}\n\nfunction parseLabelKeys(raw: Record<string, string>): Record<string | number, string> {\n return Object.entries(raw).reduce<Record<string | number, string>>((acc, [k, v]) => {\n try {\n const parsed = JSON.parse(k);\n acc[Array.isArray(parsed) ? parsed[0] : parsed] = v;\n } catch {\n acc[k] = v;\n }\n return acc;\n }, {});\n}\n"],"mappings":";;;;;;AAQA,MAAM,UAAU;AAChB,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;AAoB5B,SAAgB,uBACd,QACA,MACiE;CAYjE,MAAM,UAVJ,WAAW,KAAA,IACP,kBAAkB,KAAA,GAAW,IAAI,IACjC,oBAAoB,MAAM,IACxB,SACA,kBAAkB,QAAQ,IAAI,EAAA,CAGnC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;EAAE,MAAM;EAAS,OAAO,YAAY;CAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAC5E,WAEoB,CAAC,CAAC,QAAsD,KAAK,QAAQ;EAC1F,IAAI,CAAC,iBAAiB,GAAG,GAAG,OAAO;EACnC,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,KAAK,SAAS,WAAW,GAAG,OAAO;EAEvC,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,EAAE,gBAAgB,mBAAmB,OAAO;EAEhD,MAAM,WAAW,aAAa,IAAI;EAClC,IAAI,CAAC,UAAU,OAAO;EAEtB,IAAI,IAAI,mBAAmB,UAAU,KAAK,SAAS,EAAE,CAAC,GAAG,QAAQ;EACjE,OAAO;CACT,mBAAG,IAAI,IAAI,CAAC;CAEZ,QAAQ,WAAW,OAAO,IAAI,mBAAmB,MAAM,CAAC;AAC1D;AAEA,SAAS,aAAa,KAAoE;CACxF,MAAM,KAAK,IAAI,aAAa;CAE5B,IAAI,OAAO,SAAS;EAClB,MAAM,OAAO,IAAI,cAAiD;EAClE,OAAO,MAAM,OAAO,eAAe,KAAK,IAAI,IAAI,KAAA;CAClD;CAEA,IAAI,OAAO,qBACT,OAAO,IAAI,gBAAgB,CAAC,CAAC,QAAyC,QAAQ,YAAY;EACxF,MAAM,OAAO,IAAI,QAAQ;GACvB,OAAO;GACP,iBAAiB;GACjB,aAAa;EACf,CAAC;EACD,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,OAAO,KAAK,cAAiD;EACnE,IAAI,CAAC,MAAM,MAAM,OAAO;EACxB,OAAO,OAAO,OAAO,QAAQ,eAAe,KAAK,IAAI,CAAC;CACxD,GAAG,CAAC,CAAC;AAIT;AAEA,SAAS,eAAe,KAA8D;CACpF,OAAO,OAAO,QAAQ,GAAG,CAAC,CAAC,QAAyC,KAAK,CAAC,GAAG,OAAO;EAClF,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,CAAC;GAC3B,IAAI,MAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,UAAU;EACpD,QAAQ;GACN,IAAI,KAAK;EACX;EACA,OAAO;CACT,GAAG,CAAC,CAAC;AACP"}
|
package/dist/columns/index.cjs
CHANGED
|
@@ -3,27 +3,27 @@ const require_column_discovered_recipe = require("./column_recipes/column_discov
|
|
|
3
3
|
const require_column_filtered_recipe = require("./column_recipes/column_filtered_recipe.cjs");
|
|
4
4
|
const require_index = require("./column_recipes/index.cjs");
|
|
5
5
|
const require_column_overrided_recipe = require("./column_recipes/column_overrided_recipe.cjs");
|
|
6
|
-
const
|
|
6
|
+
const require_data_column = require("./data_column.cjs");
|
|
7
7
|
const require_providers = require("./column_providers/providers.cjs");
|
|
8
8
|
const require_index$1 = require("./column_providers/index.cjs");
|
|
9
9
|
const require_columns_collection = require("./columns_collection.cjs");
|
|
10
10
|
const require_utils = require("./utils.cjs");
|
|
11
|
-
const require_expand_by_partition = require("./expand_by_partition.cjs");
|
|
12
11
|
const require_derive_axis_values_labels = require("./derive_axis_values_labels.cjs");
|
|
12
|
+
const require_split_by_axes = require("./split_by_axes.cjs");
|
|
13
13
|
exports.AccessorColumnsProvider = require_providers.AccessorColumnsProvider;
|
|
14
14
|
exports.AccessorColumnsProviderImpl = require_providers.AccessorColumnsProviderImpl;
|
|
15
15
|
exports.ArrayColumnsProvider = require_providers.ArrayColumnsProvider;
|
|
16
16
|
exports.Column = require_column.Column;
|
|
17
|
-
exports.ColumnAbsentError =
|
|
17
|
+
exports.ColumnAbsentError = require_data_column.ColumnAbsentError;
|
|
18
18
|
exports.ColumnDiscoveredRecipe = require_column_discovered_recipe.ColumnDiscoveredRecipe;
|
|
19
19
|
exports.ColumnFilteredRecipe = require_column_filtered_recipe.ColumnFilteredRecipe;
|
|
20
|
-
exports.ColumnLazy = require_column_lazy.ColumnLazy;
|
|
21
|
-
exports.ColumnLazyImpl = require_column_lazy.ColumnLazyImpl;
|
|
22
20
|
exports.ColumnOverriddenRecipe = require_column_overrided_recipe.ColumnOverriddenRecipe;
|
|
23
21
|
exports.ColumnRecipe = require_index.ColumnRecipe;
|
|
24
22
|
exports.ColumnsCollection = require_columns_collection.ColumnsCollection;
|
|
25
23
|
exports.ColumnsCollectionImpl = require_columns_collection.ColumnsCollectionImpl;
|
|
26
24
|
exports.ColumnsProvider = require_providers.ColumnsProvider;
|
|
25
|
+
exports.DataColumn = require_data_column.DataColumn;
|
|
26
|
+
exports.DataColumnImpl = require_data_column.DataColumnImpl;
|
|
27
27
|
exports.ResultPoolColumnsProvider = require_providers.ResultPoolColumnsProvider;
|
|
28
28
|
exports.ResultPoolColumnsProviderImpl = require_providers.ResultPoolColumnsProviderImpl;
|
|
29
29
|
exports._ctxProvidersCache = require_index$1._ctxProvidersCache;
|
|
@@ -31,16 +31,16 @@ exports.collectLinkerColumns = require_utils.collectLinkerColumns;
|
|
|
31
31
|
exports.collectLinkerIds = require_utils.collectLinkerIds;
|
|
32
32
|
exports.deriveAxisValuesLabels = require_derive_axis_values_labels.deriveAxisValuesLabels;
|
|
33
33
|
exports.deriveColumnOptions = require_utils.deriveColumnOptions;
|
|
34
|
-
exports.expandByPartition = require_expand_by_partition.expandByPartition;
|
|
35
34
|
exports.getCtxProviders = require_index$1.getCtxProviders;
|
|
36
|
-
exports.getLeafColumnData = require_utils.getLeafColumnData;
|
|
37
35
|
exports.hasColumnData = require_utils.hasColumnData;
|
|
36
|
+
exports.hasReachableData = require_utils.hasReachableData;
|
|
37
|
+
exports.hasSingleDataColumn = require_utils.hasSingleDataColumn;
|
|
38
38
|
exports.hitQualifications = require_utils.hitQualifications;
|
|
39
39
|
exports.isColumn = require_column.isColumn;
|
|
40
|
-
exports.isColumnLazy = require_column_lazy.isColumnLazy;
|
|
41
40
|
exports.isColumnProvider = require_index$1.isColumnProvider;
|
|
42
|
-
exports.isColumnRecipe = require_index.isColumnRecipe;
|
|
43
41
|
exports.isColumnsCollection = require_columns_collection.isColumnsCollection;
|
|
42
|
+
exports.isDataColumn = require_data_column.isDataColumn;
|
|
44
43
|
exports.isLeafColumn = require_utils.isLeafColumn;
|
|
45
44
|
exports.queriesQualifications = require_utils.queriesQualifications;
|
|
45
|
+
exports.splitByAxes = require_split_by_axes.splitByAxes;
|
|
46
46
|
exports.toColumnProvider = require_index$1.toColumnProvider;
|
package/dist/columns/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { ColumnFieldStatus, ColumnRecipeId, ColumnResolutionStatus, SpecQuery } from "./column_recipes/types.js";
|
|
2
|
-
import { ColumnAbsentError,
|
|
2
|
+
import { ColumnAbsentError, ColumnData, DataColumn, DataColumnId, DataColumnImpl, DataColumnRecipe, DataColumnSource, isDataColumn } from "./data_column.js";
|
|
3
3
|
import { ColumnDiscoveredRecipe } from "./column_recipes/column_discovered_recipe.js";
|
|
4
4
|
import { ColumnFilteredRecipe } from "./column_recipes/column_filtered_recipe.js";
|
|
5
5
|
import { Column, ColumnSource, isColumn } from "./column.js";
|
|
6
6
|
import { ColumnOverriddenRecipe } from "./column_recipes/column_overrided_recipe.js";
|
|
7
|
-
import { ColumnRecipe
|
|
7
|
+
import { ColumnRecipe } from "./column_recipes/index.js";
|
|
8
8
|
import { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, ColumnsProvider, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl } from "./column_providers/providers.js";
|
|
9
9
|
import { ColumnsSource } from "./column_providers/types.js";
|
|
10
10
|
import { _ctxProvidersCache, getCtxProviders, isColumnProvider, toColumnProvider } from "./column_providers/index.js";
|
|
11
|
-
import {
|
|
11
|
+
import { SplitAxis, SplitByAxesOpts, splitByAxes } from "./split_by_axes.js";
|
|
12
12
|
import { ColumnsCollection, ColumnsCollectionDeps, ColumnsCollectionImpl, ColumnsSourceShorthand, isColumnsCollection } from "./columns_collection.js";
|
|
13
13
|
import { deriveAxisValuesLabels } from "./derive_axis_values_labels.js";
|
|
14
|
-
import { ColumnOption, collectLinkerColumns, collectLinkerIds, deriveColumnOptions,
|
|
15
|
-
export { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, Column, ColumnAbsentError, ColumnDiscoveredRecipe, type ColumnFieldStatus, ColumnFilteredRecipe,
|
|
14
|
+
import { ColumnOption, collectLinkerColumns, collectLinkerIds, deriveColumnOptions, hasColumnData, hasReachableData, hasSingleDataColumn, hitQualifications, isLeafColumn, queriesQualifications } from "./utils.js";
|
|
15
|
+
export { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, Column, ColumnAbsentError, ColumnData, ColumnDiscoveredRecipe, type ColumnFieldStatus, ColumnFilteredRecipe, ColumnOption, ColumnOverriddenRecipe, ColumnRecipe, type ColumnRecipeId, type ColumnResolutionStatus, ColumnSource, ColumnsCollection, ColumnsCollectionDeps, ColumnsCollectionImpl, ColumnsProvider, ColumnsSource, ColumnsSourceShorthand, DataColumn, DataColumnId, DataColumnImpl, DataColumnRecipe, DataColumnSource, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl, type SpecQuery, SplitAxis, SplitByAxesOpts, _ctxProvidersCache, collectLinkerColumns, collectLinkerIds, deriveAxisValuesLabels, deriveColumnOptions, getCtxProviders, hasColumnData, hasReachableData, hasSingleDataColumn, hitQualifications, isColumn, isColumnProvider, isColumnsCollection, isDataColumn, isLeafColumn, queriesQualifications, splitByAxes, toColumnProvider };
|
package/dist/columns/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Column, isColumn } from "./column.js";
|
|
2
2
|
import { ColumnDiscoveredRecipe } from "./column_recipes/column_discovered_recipe.js";
|
|
3
3
|
import { ColumnFilteredRecipe } from "./column_recipes/column_filtered_recipe.js";
|
|
4
|
-
import { ColumnRecipe
|
|
4
|
+
import { ColumnRecipe } from "./column_recipes/index.js";
|
|
5
5
|
import { ColumnOverriddenRecipe } from "./column_recipes/column_overrided_recipe.js";
|
|
6
|
-
import { ColumnAbsentError,
|
|
6
|
+
import { ColumnAbsentError, DataColumn, DataColumnImpl, isDataColumn } from "./data_column.js";
|
|
7
7
|
import { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, ColumnsProvider, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl } from "./column_providers/providers.js";
|
|
8
8
|
import { _ctxProvidersCache, getCtxProviders, isColumnProvider, toColumnProvider } from "./column_providers/index.js";
|
|
9
9
|
import { ColumnsCollection, ColumnsCollectionImpl, isColumnsCollection } from "./columns_collection.js";
|
|
10
|
-
import { collectLinkerColumns, collectLinkerIds, deriveColumnOptions,
|
|
11
|
-
import { expandByPartition } from "./expand_by_partition.js";
|
|
10
|
+
import { collectLinkerColumns, collectLinkerIds, deriveColumnOptions, hasColumnData, hasReachableData, hasSingleDataColumn, hitQualifications, isLeafColumn, queriesQualifications } from "./utils.js";
|
|
12
11
|
import { deriveAxisValuesLabels } from "./derive_axis_values_labels.js";
|
|
13
|
-
|
|
12
|
+
import { splitByAxes } from "./split_by_axes.js";
|
|
13
|
+
export { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, Column, ColumnAbsentError, ColumnDiscoveredRecipe, ColumnFilteredRecipe, ColumnOverriddenRecipe, ColumnRecipe, ColumnsCollection, ColumnsCollectionImpl, ColumnsProvider, DataColumn, DataColumnImpl, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl, _ctxProvidersCache, collectLinkerColumns, collectLinkerIds, deriveAxisValuesLabels, deriveColumnOptions, getCtxProviders, hasColumnData, hasReachableData, hasSingleDataColumn, hitQualifications, isColumn, isColumnProvider, isColumnsCollection, isDataColumn, isLeafColumn, queriesQualifications, splitByAxes, toColumnProvider };
|
|
@@ -3,12 +3,16 @@ const require_pcolumn_data = require("../render/util/pcolumn_data.cjs");
|
|
|
3
3
|
const require_column_filtered_recipe = require("./column_recipes/column_filtered_recipe.cjs");
|
|
4
4
|
const require_column_overrided_recipe = require("./column_recipes/column_overrided_recipe.cjs");
|
|
5
5
|
const require_utils = require("./utils.cjs");
|
|
6
|
+
const require_derive_axis_values_labels = require("./derive_axis_values_labels.cjs");
|
|
6
7
|
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
7
|
-
//#region src/columns/
|
|
8
|
+
//#region src/columns/split_by_axes.ts
|
|
8
9
|
const MAX_KEY_COMBINATIONS = 1e4;
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
* {@link ColumnRecipe} per Cartesian combination of
|
|
11
|
+
* Split each input column along the requested axes into one
|
|
12
|
+
* {@link ColumnRecipe} per Cartesian combination of the axes' distinct values.
|
|
13
|
+
*
|
|
14
|
+
* The split axes must be partition-key axes of the input's data — the distinct
|
|
15
|
+
* values are read off the partition keys.
|
|
12
16
|
*
|
|
13
17
|
* Each split is produced as `ColumnOverriddenRecipe.wrap(ColumnFilteredRecipe.wrap(inner, axisFilters), { domain, annotations })`:
|
|
14
18
|
* - `ColumnFilteredRecipe` pins all split axes at once (one wrap call with
|
|
@@ -26,13 +30,14 @@ const MAX_KEY_COMBINATIONS = 1e4;
|
|
|
26
30
|
* Returns `undefined` when any input's `getData()` is not a
|
|
27
31
|
* {@link TreeNodeAccessor} — partition inspection is not yet possible.
|
|
28
32
|
*/
|
|
29
|
-
function
|
|
33
|
+
function splitByAxes(inputs, splitAxes, opts) {
|
|
30
34
|
if (splitAxes.length === 0) return [...inputs];
|
|
35
|
+
const axisValuesLabels = opts?.axisValuesLabels ?? require_derive_axis_values_labels.deriveAxisValuesLabels();
|
|
31
36
|
const splitAxisIdxs = splitAxes.map((a) => a.idx).sort((a, b) => a - b);
|
|
32
37
|
const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];
|
|
33
38
|
const result = [];
|
|
34
39
|
for (const inner of inputs) {
|
|
35
|
-
const data = require_utils.
|
|
40
|
+
const data = require_utils.hasReachableData(inner) ? inner.getData() : void 0;
|
|
36
41
|
if (!(data instanceof require_accessor.TreeNodeAccessor) && !(0, _milaboratories_pl_model_common.isDataInfoEntries)(data)) return;
|
|
37
42
|
const uniqueKeys = require_pcolumn_data.getUniquePartitionKeys(data);
|
|
38
43
|
if (uniqueKeys === void 0) return void 0;
|
|
@@ -41,7 +46,7 @@ function expandByPartition(inputs, splitAxes, opts) {
|
|
|
41
46
|
const axesSpec = spec.axesSpec;
|
|
42
47
|
const splitAxisSpecs = splitAxisIdxs.map((idx) => axesSpec[idx]);
|
|
43
48
|
const splitAxisIds = splitAxisSpecs.map((axisSpec) => (0, _milaboratories_pl_model_common.getAxisId)(axisSpec));
|
|
44
|
-
const axesLabels = splitAxisIds.map((axisId) =>
|
|
49
|
+
const axesLabels = splitAxisIds.map((axisId) => axisValuesLabels(axisId));
|
|
45
50
|
const existingTraceRaw = (0, _milaboratories_pl_model_common.readAnnotation)(spec, _milaboratories_pl_model_common.Annotation.Trace);
|
|
46
51
|
const baseTrace = existingTraceRaw ? JSON.parse(existingTraceRaw) ?? [] : [];
|
|
47
52
|
const keyCombinations = generateKeyCombinations(uniqueKeys, splitAxisIdxs);
|
|
@@ -97,6 +102,6 @@ function generateKeyCombinations(uniqueKeys, splitAxisIdxs) {
|
|
|
97
102
|
return combinations;
|
|
98
103
|
}
|
|
99
104
|
//#endregion
|
|
100
|
-
exports.
|
|
105
|
+
exports.splitByAxes = splitByAxes;
|
|
101
106
|
|
|
102
|
-
//# sourceMappingURL=
|
|
107
|
+
//# sourceMappingURL=split_by_axes.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split_by_axes.cjs","names":["deriveAxisValuesLabels","hasReachableData","TreeNodeAccessor","getUniquePartitionKeys","Annotation","ColumnFilteredRecipe","ColumnOverriddenRecipe"],"sources":["../../src/columns/split_by_axes.ts"],"sourcesContent":["import type {\n AxisFilterByIdx,\n AxisFilterValue,\n AxisId,\n TraceEntry,\n} from \"@milaboratories/pl-model-common\";\nimport {\n Annotation,\n canonicalizeAxisId,\n getAxisId,\n isDataInfoEntries,\n readAnnotation,\n} from \"@milaboratories/pl-model-common\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport { getUniquePartitionKeys } from \"../render/util/pcolumn_data\";\nimport { deriveAxisValuesLabels } from \"./derive_axis_values_labels\";\nimport type { ColumnRecipe } from \"./column_recipes\";\nimport { ColumnFilteredRecipe } from \"./column_recipes/column_filtered_recipe\";\nimport { ColumnOverriddenRecipe } from \"./column_recipes/column_overrided_recipe\";\nimport { Column } from \"./column\";\nimport { hasReachableData } from \"./utils\";\n\n// --- Types ---\n\nexport interface SplitAxis {\n /** Index of the axis in the column's axesSpec to split by. */\n readonly idx: number;\n}\n\nexport interface SplitByAxesOpts {\n /**\n * Resolve axis values to human-readable labels.\n *\n * Defaults to {@link deriveAxisValuesLabels} over the ambient render ctx\n * (current block outputs + result pool), resolved lazily on the first\n * lookup. Pass an explicit callback to narrow the label source, or\n * `() => undefined` to keep raw axis values.\n */\n axisValuesLabels?: (axisId: AxisId) => undefined | Record<string | number, string>;\n}\n\n// --- Implementation ---\n\nconst MAX_KEY_COMBINATIONS = 10_000;\n\n/**\n * Split each input column along the requested axes into one\n * {@link ColumnRecipe} per Cartesian combination of the axes' distinct values.\n *\n * The split axes must be partition-key axes of the input's data — the distinct\n * values are read off the partition keys.\n *\n * Each split is produced as `ColumnOverriddenRecipe.wrap(ColumnFilteredRecipe.wrap(inner, axisFilters), { domain, annotations })`:\n * - `ColumnFilteredRecipe` pins all split axes at once (one wrap call with\n * every `[idx, value]` pair) and removes them from `axesSpec`. The\n * engine performs the data slicing via the `sliceAxes` query node.\n * - `ColumnOverriddenRecipe` overlays a `domain[axisName] = String(value)`\n * entry per split axis and appends a `split:<canonicalAxisId>` trace\n * entry per split axis to the existing `pl7.app/trace` annotation.\n *\n * The recipe id is a canonical\n * `ColumnOverriddenId(source: ColumnFilteredId(source: inner.id, axisFilters), specOverrides)`\n * — distinct per split combination, parseable by `extractPObjectId`, and\n * traversable by recipe walkers.\n *\n * Returns `undefined` when any input's `getData()` is not a\n * {@link TreeNodeAccessor} — partition inspection is not yet possible.\n */\nexport function splitByAxes(\n inputs: Column[],\n splitAxes: SplitAxis[],\n opts?: SplitByAxesOpts,\n): ColumnRecipe[] | undefined {\n if (splitAxes.length === 0) {\n return [...inputs];\n }\n\n const axisValuesLabels = opts?.axisValuesLabels ?? deriveAxisValuesLabels();\n\n const splitAxisIdxs = splitAxes.map((a) => a.idx).sort((a, b) => a - b);\n const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];\n\n const result: ColumnRecipe[] = [];\n\n for (const inner of inputs) {\n const data = hasReachableData(inner) ? inner.getData() : undefined;\n // Partition inspection requires either a live tree-accessor or already\n // parsed DataInfoEntries. Anything else means the input is not yet ready.\n if (!(data instanceof TreeNodeAccessor) && !isDataInfoEntries(data)) {\n return undefined;\n }\n\n const uniqueKeys = getUniquePartitionKeys(data);\n if (uniqueKeys === undefined) return undefined;\n\n if (maxSplitIdx >= uniqueKeys.length) {\n throw new Error(\n `Not enough partition keys (${uniqueKeys.length}) for requested split axes (max index ${maxSplitIdx}) in column ${inner.getSpec().name}`,\n );\n }\n\n const spec = inner.getSpec();\n const axesSpec = spec.axesSpec;\n const splitAxisSpecs = splitAxisIdxs.map((idx) => axesSpec[idx]);\n const splitAxisIds = splitAxisSpecs.map((axisSpec) => getAxisId(axisSpec));\n const axesLabels = splitAxisIds.map((axisId) => axisValuesLabels(axisId));\n\n const existingTraceRaw = readAnnotation(spec, Annotation.Trace);\n const baseTrace: TraceEntry[] = existingTraceRaw\n ? ((JSON.parse(existingTraceRaw) as TraceEntry[]) ?? [])\n : [];\n\n const keyCombinations = generateKeyCombinations(uniqueKeys, splitAxisIdxs);\n if (keyCombinations.length === 0) continue;\n\n for (const keyCombo of keyCombinations) {\n const axisFilters: AxisFilterByIdx[] = keyCombo.map(\n (value, sAxisIdx): AxisFilterByIdx => [splitAxisIdxs[sAxisIdx], value as AxisFilterValue],\n );\n\n const domain: Record<string, string> = {};\n const traceEntries: TraceEntry[] = [];\n for (let sAxisIdx = 0; sAxisIdx < keyCombo.length; sAxisIdx++) {\n const value = keyCombo[sAxisIdx];\n const axisSpec = splitAxisSpecs[sAxisIdx];\n const axisId = splitAxisIds[sAxisIdx];\n const labelMap = axesLabels[sAxisIdx];\n const label = labelMap?.[value] ?? String(value);\n domain[axisSpec.name] = String(value);\n traceEntries.push({\n type: `split:${canonicalizeAxisId(axisId)}`,\n label,\n importance: 1_000_000,\n });\n }\n\n const filtered = ColumnFilteredRecipe.wrap(inner, axisFilters);\n const overrided = ColumnOverriddenRecipe.wrap(filtered, {\n domain,\n annotations: {\n [Annotation.Trace]: JSON.stringify([...baseTrace, ...traceEntries]),\n },\n });\n\n result.push(overrided);\n }\n }\n\n return result;\n}\n\nfunction generateKeyCombinations(\n uniqueKeys: (string | number)[][],\n splitAxisIdxs: number[],\n): (string | number)[][] {\n const combinations: (string | number)[][] = [];\n\n function generate(currentCombo: (string | number)[], sAxisIdx: number): void {\n if (sAxisIdx >= splitAxisIdxs.length) {\n combinations.push([...currentCombo]);\n if (combinations.length > MAX_KEY_COMBINATIONS) {\n throw new Error(\"Too many key combinations, aborting.\");\n }\n return;\n }\n\n const axisIdx = splitAxisIdxs[sAxisIdx];\n if (axisIdx >= uniqueKeys.length) {\n throw new Error(\n `Axis index ${axisIdx} out of bounds for unique keys array (length ${uniqueKeys.length})`,\n );\n }\n\n const axisValues = uniqueKeys[axisIdx];\n if (!axisValues || axisValues.length === 0) {\n combinations.length = 0;\n return;\n }\n\n for (const val of axisValues) {\n currentCombo.push(val);\n generate(currentCombo, sAxisIdx + 1);\n currentCombo.pop();\n }\n }\n\n generate([], 0);\n return combinations;\n}\n"],"mappings":"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"}
|
|
@@ -2,18 +2,28 @@ import { Column } from "./column.js";
|
|
|
2
2
|
import { ColumnRecipe } from "./column_recipes/index.js";
|
|
3
3
|
import { AxisId } from "@milaboratories/pl-model-common";
|
|
4
4
|
|
|
5
|
-
//#region src/columns/
|
|
5
|
+
//#region src/columns/split_by_axes.d.ts
|
|
6
6
|
interface SplitAxis {
|
|
7
7
|
/** Index of the axis in the column's axesSpec to split by. */
|
|
8
8
|
readonly idx: number;
|
|
9
9
|
}
|
|
10
|
-
interface
|
|
11
|
-
/**
|
|
10
|
+
interface SplitByAxesOpts {
|
|
11
|
+
/**
|
|
12
|
+
* Resolve axis values to human-readable labels.
|
|
13
|
+
*
|
|
14
|
+
* Defaults to {@link deriveAxisValuesLabels} over the ambient render ctx
|
|
15
|
+
* (current block outputs + result pool), resolved lazily on the first
|
|
16
|
+
* lookup. Pass an explicit callback to narrow the label source, or
|
|
17
|
+
* `() => undefined` to keep raw axis values.
|
|
18
|
+
*/
|
|
12
19
|
axisValuesLabels?: (axisId: AxisId) => undefined | Record<string | number, string>;
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
15
|
-
*
|
|
16
|
-
* {@link ColumnRecipe} per Cartesian combination of
|
|
22
|
+
* Split each input column along the requested axes into one
|
|
23
|
+
* {@link ColumnRecipe} per Cartesian combination of the axes' distinct values.
|
|
24
|
+
*
|
|
25
|
+
* The split axes must be partition-key axes of the input's data — the distinct
|
|
26
|
+
* values are read off the partition keys.
|
|
17
27
|
*
|
|
18
28
|
* Each split is produced as `ColumnOverriddenRecipe.wrap(ColumnFilteredRecipe.wrap(inner, axisFilters), { domain, annotations })`:
|
|
19
29
|
* - `ColumnFilteredRecipe` pins all split axes at once (one wrap call with
|
|
@@ -31,7 +41,7 @@ interface ExpandByPartitionOpts {
|
|
|
31
41
|
* Returns `undefined` when any input's `getData()` is not a
|
|
32
42
|
* {@link TreeNodeAccessor} — partition inspection is not yet possible.
|
|
33
43
|
*/
|
|
34
|
-
declare function
|
|
44
|
+
declare function splitByAxes(inputs: Column[], splitAxes: SplitAxis[], opts?: SplitByAxesOpts): ColumnRecipe[] | undefined;
|
|
35
45
|
//#endregion
|
|
36
|
-
export {
|
|
37
|
-
//# sourceMappingURL=
|
|
46
|
+
export { SplitAxis, SplitByAxesOpts, splitByAxes };
|
|
47
|
+
//# sourceMappingURL=split_by_axes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split_by_axes.d.ts","names":[],"sources":["../../src/columns/split_by_axes.ts"],"mappings":";;;;;UAwBiB,SAAA;;WAEN,GAAG;AAAA;AAAA,UAGG,eAAA;EAHH;AAAA;AAGd;;;;;;EASE,gBAAA,IAAoB,MAAA,EAAQ,MAAA,iBAAuB,MAAM;AAAA;;AAAA;AA8B3D;;;;;;;;;;;;;;;;;AAIe;;;;iBAJC,WAAA,CACd,MAAA,EAAQ,MAAA,IACR,SAAA,EAAW,SAAA,IACX,IAAA,GAAO,eAAA,GACN,YAAA"}
|
|
@@ -2,13 +2,17 @@ import { TreeNodeAccessor } from "../render/accessor.js";
|
|
|
2
2
|
import { getUniquePartitionKeys } from "../render/util/pcolumn_data.js";
|
|
3
3
|
import { ColumnFilteredRecipe } from "./column_recipes/column_filtered_recipe.js";
|
|
4
4
|
import { ColumnOverriddenRecipe } from "./column_recipes/column_overrided_recipe.js";
|
|
5
|
-
import {
|
|
5
|
+
import { hasReachableData } from "./utils.js";
|
|
6
|
+
import { deriveAxisValuesLabels } from "./derive_axis_values_labels.js";
|
|
6
7
|
import { Annotation, canonicalizeAxisId, getAxisId, isDataInfoEntries, readAnnotation } from "@milaboratories/pl-model-common";
|
|
7
|
-
//#region src/columns/
|
|
8
|
+
//#region src/columns/split_by_axes.ts
|
|
8
9
|
const MAX_KEY_COMBINATIONS = 1e4;
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
* {@link ColumnRecipe} per Cartesian combination of
|
|
11
|
+
* Split each input column along the requested axes into one
|
|
12
|
+
* {@link ColumnRecipe} per Cartesian combination of the axes' distinct values.
|
|
13
|
+
*
|
|
14
|
+
* The split axes must be partition-key axes of the input's data — the distinct
|
|
15
|
+
* values are read off the partition keys.
|
|
12
16
|
*
|
|
13
17
|
* Each split is produced as `ColumnOverriddenRecipe.wrap(ColumnFilteredRecipe.wrap(inner, axisFilters), { domain, annotations })`:
|
|
14
18
|
* - `ColumnFilteredRecipe` pins all split axes at once (one wrap call with
|
|
@@ -26,13 +30,14 @@ const MAX_KEY_COMBINATIONS = 1e4;
|
|
|
26
30
|
* Returns `undefined` when any input's `getData()` is not a
|
|
27
31
|
* {@link TreeNodeAccessor} — partition inspection is not yet possible.
|
|
28
32
|
*/
|
|
29
|
-
function
|
|
33
|
+
function splitByAxes(inputs, splitAxes, opts) {
|
|
30
34
|
if (splitAxes.length === 0) return [...inputs];
|
|
35
|
+
const axisValuesLabels = opts?.axisValuesLabels ?? deriveAxisValuesLabels();
|
|
31
36
|
const splitAxisIdxs = splitAxes.map((a) => a.idx).sort((a, b) => a - b);
|
|
32
37
|
const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];
|
|
33
38
|
const result = [];
|
|
34
39
|
for (const inner of inputs) {
|
|
35
|
-
const data =
|
|
40
|
+
const data = hasReachableData(inner) ? inner.getData() : void 0;
|
|
36
41
|
if (!(data instanceof TreeNodeAccessor) && !isDataInfoEntries(data)) return;
|
|
37
42
|
const uniqueKeys = getUniquePartitionKeys(data);
|
|
38
43
|
if (uniqueKeys === void 0) return void 0;
|
|
@@ -41,7 +46,7 @@ function expandByPartition(inputs, splitAxes, opts) {
|
|
|
41
46
|
const axesSpec = spec.axesSpec;
|
|
42
47
|
const splitAxisSpecs = splitAxisIdxs.map((idx) => axesSpec[idx]);
|
|
43
48
|
const splitAxisIds = splitAxisSpecs.map((axisSpec) => getAxisId(axisSpec));
|
|
44
|
-
const axesLabels = splitAxisIds.map((axisId) =>
|
|
49
|
+
const axesLabels = splitAxisIds.map((axisId) => axisValuesLabels(axisId));
|
|
45
50
|
const existingTraceRaw = readAnnotation(spec, Annotation.Trace);
|
|
46
51
|
const baseTrace = existingTraceRaw ? JSON.parse(existingTraceRaw) ?? [] : [];
|
|
47
52
|
const keyCombinations = generateKeyCombinations(uniqueKeys, splitAxisIdxs);
|
|
@@ -97,6 +102,6 @@ function generateKeyCombinations(uniqueKeys, splitAxisIdxs) {
|
|
|
97
102
|
return combinations;
|
|
98
103
|
}
|
|
99
104
|
//#endregion
|
|
100
|
-
export {
|
|
105
|
+
export { splitByAxes };
|
|
101
106
|
|
|
102
|
-
//# sourceMappingURL=
|
|
107
|
+
//# sourceMappingURL=split_by_axes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split_by_axes.js","names":[],"sources":["../../src/columns/split_by_axes.ts"],"sourcesContent":["import type {\n AxisFilterByIdx,\n AxisFilterValue,\n AxisId,\n TraceEntry,\n} from \"@milaboratories/pl-model-common\";\nimport {\n Annotation,\n canonicalizeAxisId,\n getAxisId,\n isDataInfoEntries,\n readAnnotation,\n} from \"@milaboratories/pl-model-common\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport { getUniquePartitionKeys } from \"../render/util/pcolumn_data\";\nimport { deriveAxisValuesLabels } from \"./derive_axis_values_labels\";\nimport type { ColumnRecipe } from \"./column_recipes\";\nimport { ColumnFilteredRecipe } from \"./column_recipes/column_filtered_recipe\";\nimport { ColumnOverriddenRecipe } from \"./column_recipes/column_overrided_recipe\";\nimport { Column } from \"./column\";\nimport { hasReachableData } from \"./utils\";\n\n// --- Types ---\n\nexport interface SplitAxis {\n /** Index of the axis in the column's axesSpec to split by. */\n readonly idx: number;\n}\n\nexport interface SplitByAxesOpts {\n /**\n * Resolve axis values to human-readable labels.\n *\n * Defaults to {@link deriveAxisValuesLabels} over the ambient render ctx\n * (current block outputs + result pool), resolved lazily on the first\n * lookup. Pass an explicit callback to narrow the label source, or\n * `() => undefined` to keep raw axis values.\n */\n axisValuesLabels?: (axisId: AxisId) => undefined | Record<string | number, string>;\n}\n\n// --- Implementation ---\n\nconst MAX_KEY_COMBINATIONS = 10_000;\n\n/**\n * Split each input column along the requested axes into one\n * {@link ColumnRecipe} per Cartesian combination of the axes' distinct values.\n *\n * The split axes must be partition-key axes of the input's data — the distinct\n * values are read off the partition keys.\n *\n * Each split is produced as `ColumnOverriddenRecipe.wrap(ColumnFilteredRecipe.wrap(inner, axisFilters), { domain, annotations })`:\n * - `ColumnFilteredRecipe` pins all split axes at once (one wrap call with\n * every `[idx, value]` pair) and removes them from `axesSpec`. The\n * engine performs the data slicing via the `sliceAxes` query node.\n * - `ColumnOverriddenRecipe` overlays a `domain[axisName] = String(value)`\n * entry per split axis and appends a `split:<canonicalAxisId>` trace\n * entry per split axis to the existing `pl7.app/trace` annotation.\n *\n * The recipe id is a canonical\n * `ColumnOverriddenId(source: ColumnFilteredId(source: inner.id, axisFilters), specOverrides)`\n * — distinct per split combination, parseable by `extractPObjectId`, and\n * traversable by recipe walkers.\n *\n * Returns `undefined` when any input's `getData()` is not a\n * {@link TreeNodeAccessor} — partition inspection is not yet possible.\n */\nexport function splitByAxes(\n inputs: Column[],\n splitAxes: SplitAxis[],\n opts?: SplitByAxesOpts,\n): ColumnRecipe[] | undefined {\n if (splitAxes.length === 0) {\n return [...inputs];\n }\n\n const axisValuesLabels = opts?.axisValuesLabels ?? deriveAxisValuesLabels();\n\n const splitAxisIdxs = splitAxes.map((a) => a.idx).sort((a, b) => a - b);\n const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];\n\n const result: ColumnRecipe[] = [];\n\n for (const inner of inputs) {\n const data = hasReachableData(inner) ? inner.getData() : undefined;\n // Partition inspection requires either a live tree-accessor or already\n // parsed DataInfoEntries. Anything else means the input is not yet ready.\n if (!(data instanceof TreeNodeAccessor) && !isDataInfoEntries(data)) {\n return undefined;\n }\n\n const uniqueKeys = getUniquePartitionKeys(data);\n if (uniqueKeys === undefined) return undefined;\n\n if (maxSplitIdx >= uniqueKeys.length) {\n throw new Error(\n `Not enough partition keys (${uniqueKeys.length}) for requested split axes (max index ${maxSplitIdx}) in column ${inner.getSpec().name}`,\n );\n }\n\n const spec = inner.getSpec();\n const axesSpec = spec.axesSpec;\n const splitAxisSpecs = splitAxisIdxs.map((idx) => axesSpec[idx]);\n const splitAxisIds = splitAxisSpecs.map((axisSpec) => getAxisId(axisSpec));\n const axesLabels = splitAxisIds.map((axisId) => axisValuesLabels(axisId));\n\n const existingTraceRaw = readAnnotation(spec, Annotation.Trace);\n const baseTrace: TraceEntry[] = existingTraceRaw\n ? ((JSON.parse(existingTraceRaw) as TraceEntry[]) ?? [])\n : [];\n\n const keyCombinations = generateKeyCombinations(uniqueKeys, splitAxisIdxs);\n if (keyCombinations.length === 0) continue;\n\n for (const keyCombo of keyCombinations) {\n const axisFilters: AxisFilterByIdx[] = keyCombo.map(\n (value, sAxisIdx): AxisFilterByIdx => [splitAxisIdxs[sAxisIdx], value as AxisFilterValue],\n );\n\n const domain: Record<string, string> = {};\n const traceEntries: TraceEntry[] = [];\n for (let sAxisIdx = 0; sAxisIdx < keyCombo.length; sAxisIdx++) {\n const value = keyCombo[sAxisIdx];\n const axisSpec = splitAxisSpecs[sAxisIdx];\n const axisId = splitAxisIds[sAxisIdx];\n const labelMap = axesLabels[sAxisIdx];\n const label = labelMap?.[value] ?? String(value);\n domain[axisSpec.name] = String(value);\n traceEntries.push({\n type: `split:${canonicalizeAxisId(axisId)}`,\n label,\n importance: 1_000_000,\n });\n }\n\n const filtered = ColumnFilteredRecipe.wrap(inner, axisFilters);\n const overrided = ColumnOverriddenRecipe.wrap(filtered, {\n domain,\n annotations: {\n [Annotation.Trace]: JSON.stringify([...baseTrace, ...traceEntries]),\n },\n });\n\n result.push(overrided);\n }\n }\n\n return result;\n}\n\nfunction generateKeyCombinations(\n uniqueKeys: (string | number)[][],\n splitAxisIdxs: number[],\n): (string | number)[][] {\n const combinations: (string | number)[][] = [];\n\n function generate(currentCombo: (string | number)[], sAxisIdx: number): void {\n if (sAxisIdx >= splitAxisIdxs.length) {\n combinations.push([...currentCombo]);\n if (combinations.length > MAX_KEY_COMBINATIONS) {\n throw new Error(\"Too many key combinations, aborting.\");\n }\n return;\n }\n\n const axisIdx = splitAxisIdxs[sAxisIdx];\n if (axisIdx >= uniqueKeys.length) {\n throw new Error(\n `Axis index ${axisIdx} out of bounds for unique keys array (length ${uniqueKeys.length})`,\n );\n }\n\n const axisValues = uniqueKeys[axisIdx];\n if (!axisValues || axisValues.length === 0) {\n combinations.length = 0;\n return;\n }\n\n for (const val of axisValues) {\n currentCombo.push(val);\n generate(currentCombo, sAxisIdx + 1);\n currentCombo.pop();\n }\n }\n\n generate([], 0);\n return combinations;\n}\n"],"mappings":"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"}
|
package/dist/columns/utils.cjs
CHANGED
|
@@ -4,7 +4,7 @@ require("../render/index.cjs");
|
|
|
4
4
|
const require_column_discovered_recipe = require("./column_recipes/column_discovered_recipe.cjs");
|
|
5
5
|
const require_column_filtered_recipe = require("./column_recipes/column_filtered_recipe.cjs");
|
|
6
6
|
const require_column_overrided_recipe = require("./column_recipes/column_overrided_recipe.cjs");
|
|
7
|
-
const
|
|
7
|
+
const require_data_column = require("./data_column.cjs");
|
|
8
8
|
const require_columns_collection = require("./columns_collection.cjs");
|
|
9
9
|
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
10
10
|
let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
@@ -16,7 +16,7 @@ let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
|
16
16
|
* other engine-consumed column.
|
|
17
17
|
*
|
|
18
18
|
* Pure query walk — no registry access. Use {@link collectLinkerColumns} for
|
|
19
|
-
* the resolved {@link
|
|
19
|
+
* the resolved {@link DataColumnRecipe} variant.
|
|
20
20
|
*/
|
|
21
21
|
function collectLinkerIds(recipe) {
|
|
22
22
|
const hit = (0, _milaboratories_pl_model_common.extractPObjectId)(recipe.id);
|
|
@@ -33,11 +33,11 @@ function collectLinkerIds(recipe) {
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* {@link collectLinkerIds} resolved against the ambient context as
|
|
36
|
-
* {@link
|
|
36
|
+
* {@link DataColumnRecipe} leaves. Throws if any id fails to resolve —
|
|
37
37
|
* matches the contract of the legacy `resolveLinkers` it replaces.
|
|
38
38
|
*/
|
|
39
39
|
function collectLinkerColumns(recipe, opts = {}) {
|
|
40
|
-
return collectLinkerIds(recipe).map((id) =>
|
|
40
|
+
return collectLinkerIds(recipe).map((id) => require_data_column.DataColumnImpl.fromId(id, opts) ?? (0, _milaboratories_helpers.throwError)(`materializeLinkers: linker ${id} not resolvable`));
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Hit-side axis qualifications for the recipe — the ones that should land on
|
|
@@ -67,7 +67,7 @@ function queriesQualifications(recipe) {
|
|
|
67
67
|
*
|
|
68
68
|
* Walks every physical leaf the recipe depends on via
|
|
69
69
|
* {@link ColumnRecipe.getReferencedIds} (resolves each id back to a
|
|
70
|
-
* {@link
|
|
70
|
+
* {@link DataColumnRecipe} through the ambient ctx) and ANDs `hasData()` across
|
|
71
71
|
* all of them. Inline {@link PColumnValues} payloads count as present.
|
|
72
72
|
*
|
|
73
73
|
* Returns `false` if any leaf cannot be re-resolved in `opts.ctx` (treat as
|
|
@@ -76,14 +76,14 @@ function queriesQualifications(recipe) {
|
|
|
76
76
|
*/
|
|
77
77
|
function hasColumnData(recipe, opts = {}) {
|
|
78
78
|
for (const id of recipe.getReferencedIds()) {
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
if (
|
|
82
|
-
if (!
|
|
79
|
+
const leaf = require_data_column.DataColumnImpl.fromId(id, opts);
|
|
80
|
+
if (leaf === void 0) return false;
|
|
81
|
+
if (leaf.getDataStatus() !== "present") return false;
|
|
82
|
+
if (!isLeafDataPresent(leaf.getData())) return false;
|
|
83
83
|
}
|
|
84
84
|
return true;
|
|
85
85
|
}
|
|
86
|
-
function
|
|
86
|
+
function isLeafDataPresent(data) {
|
|
87
87
|
if (data === void 0) return false;
|
|
88
88
|
if (Array.isArray(data)) return true;
|
|
89
89
|
if (data instanceof require_accessor.TreeNodeAccessor) return data.hasData();
|
|
@@ -117,45 +117,51 @@ function findDiscovered(recipe) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
120
|
+
* Whether the recipe reads exactly one data column — its own — rather than
|
|
121
|
+
* reaching through others.
|
|
122
122
|
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
123
|
+
* True for a bare leaf and for projections over one (spec overrides, axis
|
|
124
|
+
* slicing): those add layers but no new columns. False when the recipe gets at
|
|
125
|
+
* its data through further columns, which happens when discovery reached it via
|
|
126
|
+
* a linker chain.
|
|
127
|
+
*
|
|
128
|
+
* **Why callers care.** A recipe over a single data column is co-indexed by its
|
|
129
|
+
* own axes, so its spec is the whole truth about them. One that needs other
|
|
130
|
+
* columns only lines up after they are joined in, and therefore drags axes into
|
|
131
|
+
* the join that its own spec never mentions — which is why it cannot serve as a
|
|
132
|
+
* primary column, and why `createPlDataTableV3` splits on this.
|
|
133
|
+
*
|
|
134
|
+
* The count comes from {@link ColumnRecipe.getReferencedIds}, which resolves
|
|
135
|
+
* through the whole wrapper chain, so no class walk is involved and foreign
|
|
136
|
+
* `ColumnRecipe` implementations are handled too.
|
|
127
137
|
*/
|
|
128
|
-
function
|
|
129
|
-
return
|
|
138
|
+
function hasSingleDataColumn(recipe) {
|
|
139
|
+
return recipe.getReferencedIds().length === 1;
|
|
130
140
|
}
|
|
131
141
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* {@link
|
|
135
|
-
* chain reaches a {@link ColumnDiscoveredRecipe}); the symmetric counterpart
|
|
136
|
-
* of {@link isLeafColumn} returning `false`.
|
|
142
|
+
* @deprecated Renamed to {@link hasSingleDataColumn} — "leaf" read as "you can
|
|
143
|
+
* get data out of it", which is a different question (see
|
|
144
|
+
* {@link hasReachableData}). Same semantics.
|
|
137
145
|
*/
|
|
138
|
-
|
|
139
|
-
if (!isLeafColumn(recipe)) throw new Error(`getLeafColumnData: recipe ${recipe.id} is not a leaf column`);
|
|
140
|
-
return extractLeafColumn(recipe)?.getData();
|
|
141
|
-
}
|
|
146
|
+
const isLeafColumn = hasSingleDataColumn;
|
|
142
147
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
148
|
+
* Whether the column's data can be read here and now, consistent with its
|
|
149
|
+
* spec — narrows to {@link DataColumnRecipe}, which exposes `getData()`.
|
|
150
|
+
*
|
|
151
|
+
* True for a bare leaf and for a spec-override over a bare leaf. False for an
|
|
152
|
+
* axis-filtered recipe (its spec has dropped axes the underlying data still
|
|
153
|
+
* carries, so the two no longer line up) and for anything reached through
|
|
154
|
+
* other columns (nothing to read until the engine joins them). In both of
|
|
155
|
+
* those cases the data exists only engine-side: pass `recipe.id` to
|
|
156
|
+
* `createPFrame` / `createPTable` instead of trying to read it.
|
|
157
|
+
*
|
|
158
|
+
* The distinction is settled when the recipe is built, not here — recipes that
|
|
159
|
+
* carry data are instances of a class that declares `getData`. So a `true`
|
|
160
|
+
* result narrows to a value that really has the method, and there is no
|
|
161
|
+
* throwing path behind the guard.
|
|
147
162
|
*/
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
while (true) {
|
|
151
|
-
if (current instanceof require_column_lazy.ColumnLazyImpl) return current;
|
|
152
|
-
if (current instanceof require_column_overrided_recipe.ColumnOverriddenRecipe || current instanceof require_column_filtered_recipe.ColumnFilteredRecipe) {
|
|
153
|
-
current = current.getInner();
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
if (current instanceof require_column_discovered_recipe.ColumnDiscoveredRecipe) throw new Error(`extractLeafColumn: recipe ${recipe.id} is not a leaf column`);
|
|
157
|
-
throw new Error(`extractLeafColumn: unrecognized recipe layer for ${recipe.id}`);
|
|
158
|
-
}
|
|
163
|
+
function hasReachableData(recipe) {
|
|
164
|
+
return recipe instanceof require_data_column.DataColumnImpl || recipe instanceof require_column_overrided_recipe.DataColumnOverriddenRecipe;
|
|
159
165
|
}
|
|
160
166
|
/**
|
|
161
167
|
* Enumerates every column already in `source` and renders distinct labels
|
|
@@ -177,8 +183,9 @@ function deriveColumnOptions(source, labelOptions = {}) {
|
|
|
177
183
|
exports.collectLinkerColumns = collectLinkerColumns;
|
|
178
184
|
exports.collectLinkerIds = collectLinkerIds;
|
|
179
185
|
exports.deriveColumnOptions = deriveColumnOptions;
|
|
180
|
-
exports.getLeafColumnData = getLeafColumnData;
|
|
181
186
|
exports.hasColumnData = hasColumnData;
|
|
187
|
+
exports.hasReachableData = hasReachableData;
|
|
188
|
+
exports.hasSingleDataColumn = hasSingleDataColumn;
|
|
182
189
|
exports.hitQualifications = hitQualifications;
|
|
183
190
|
exports.isLeafColumn = isLeafColumn;
|
|
184
191
|
exports.queriesQualifications = queriesQualifications;
|