@platforma-sdk/model 1.80.17 → 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.
Files changed (118) hide show
  1. package/dist/columns/column.cjs +9 -6
  2. package/dist/columns/column.cjs.map +1 -1
  3. package/dist/columns/column.d.ts +5 -5
  4. package/dist/columns/column.d.ts.map +1 -1
  5. package/dist/columns/column.js +10 -7
  6. package/dist/columns/column.js.map +1 -1
  7. package/dist/columns/column_providers/index.cjs.map +1 -1
  8. package/dist/columns/column_providers/index.d.ts.map +1 -1
  9. package/dist/columns/column_providers/index.js.map +1 -1
  10. package/dist/columns/column_providers/providers.cjs +5 -5
  11. package/dist/columns/column_providers/providers.cjs.map +1 -1
  12. package/dist/columns/column_providers/providers.d.ts +8 -8
  13. package/dist/columns/column_providers/providers.d.ts.map +1 -1
  14. package/dist/columns/column_providers/providers.js +5 -5
  15. package/dist/columns/column_providers/providers.js.map +1 -1
  16. package/dist/columns/column_providers/types.d.ts +3 -3
  17. package/dist/columns/column_providers/types.d.ts.map +1 -1
  18. package/dist/columns/column_recipes/column_discovered_recipe.cjs +1 -1
  19. package/dist/columns/column_recipes/column_discovered_recipe.cjs.map +1 -1
  20. package/dist/columns/column_recipes/column_discovered_recipe.d.ts +1 -1
  21. package/dist/columns/column_recipes/column_discovered_recipe.js +1 -1
  22. package/dist/columns/column_recipes/column_discovered_recipe.js.map +1 -1
  23. package/dist/columns/column_recipes/column_overrided_recipe.cjs +47 -2
  24. package/dist/columns/column_recipes/column_overrided_recipe.cjs.map +1 -1
  25. package/dist/columns/column_recipes/column_overrided_recipe.d.ts +30 -3
  26. package/dist/columns/column_recipes/column_overrided_recipe.d.ts.map +1 -1
  27. package/dist/columns/column_recipes/column_overrided_recipe.js +47 -3
  28. package/dist/columns/column_recipes/column_overrided_recipe.js.map +1 -1
  29. package/dist/columns/column_recipes/index.cjs +4 -14
  30. package/dist/columns/column_recipes/index.cjs.map +1 -1
  31. package/dist/columns/column_recipes/index.d.ts +3 -10
  32. package/dist/columns/column_recipes/index.d.ts.map +1 -1
  33. package/dist/columns/column_recipes/index.js +5 -14
  34. package/dist/columns/column_recipes/index.js.map +1 -1
  35. package/dist/columns/{column_lazy.cjs → data_column.cjs} +57 -54
  36. package/dist/columns/data_column.cjs.map +1 -0
  37. package/dist/columns/data_column.d.ts +152 -0
  38. package/dist/columns/data_column.d.ts.map +1 -0
  39. package/dist/columns/{column_lazy.js → data_column.js} +55 -52
  40. package/dist/columns/data_column.js.map +1 -0
  41. package/dist/columns/derive_axis_values_labels.cjs +4 -4
  42. package/dist/columns/derive_axis_values_labels.cjs.map +1 -1
  43. package/dist/columns/derive_axis_values_labels.d.ts +2 -2
  44. package/dist/columns/derive_axis_values_labels.js +4 -4
  45. package/dist/columns/derive_axis_values_labels.js.map +1 -1
  46. package/dist/columns/index.cjs +9 -9
  47. package/dist/columns/index.d.ts +5 -5
  48. package/dist/columns/index.js +5 -5
  49. package/dist/columns/{expand_by_partition.cjs → split_by_axes.cjs} +13 -8
  50. package/dist/columns/split_by_axes.cjs.map +1 -0
  51. package/dist/columns/{expand_by_partition.d.ts → split_by_axes.d.ts} +18 -8
  52. package/dist/columns/split_by_axes.d.ts.map +1 -0
  53. package/dist/columns/{expand_by_partition.js → split_by_axes.js} +14 -9
  54. package/dist/columns/split_by_axes.js.map +1 -0
  55. package/dist/columns/utils.cjs +50 -43
  56. package/dist/columns/utils.cjs.map +1 -1
  57. package/dist/columns/utils.d.ts +44 -19
  58. package/dist/columns/utils.d.ts.map +1 -1
  59. package/dist/columns/utils.js +50 -44
  60. package/dist/columns/utils.js.map +1 -1
  61. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs +3 -3
  62. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs.map +1 -1
  63. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js +3 -3
  64. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js.map +1 -1
  65. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +2 -2
  66. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -1
  67. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +2 -2
  68. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -1
  69. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +1 -1
  70. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  71. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +2 -2
  72. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  73. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +1 -1
  74. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
  75. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +2 -2
  76. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
  77. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs +1 -1
  78. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs.map +1 -1
  79. package/dist/components/PlDatasetSelector/enrichment_discovery.js +2 -2
  80. package/dist/components/PlDatasetSelector/enrichment_discovery.js.map +1 -1
  81. package/dist/index.cjs +9 -9
  82. package/dist/index.d.ts +5 -5
  83. package/dist/index.js +5 -5
  84. package/dist/package.cjs +1 -1
  85. package/dist/package.js +1 -1
  86. package/package.json +7 -7
  87. package/src/columns/__test_helpers__/collection_driver.ts +6 -6
  88. package/src/columns/__test_helpers__/stub_registry.ts +4 -6
  89. package/src/columns/column.ts +20 -9
  90. package/src/columns/column_providers/index.ts +9 -3
  91. package/src/columns/column_providers/providers.ts +16 -15
  92. package/src/columns/column_providers/types.ts +3 -3
  93. package/src/columns/column_recipes/column_discovered_recipe.ts +1 -1
  94. package/src/columns/column_recipes/column_overrided_recipe.ts +58 -4
  95. package/src/columns/column_recipes/column_recipes.test.ts +2 -2
  96. package/src/columns/column_recipes/index.ts +5 -20
  97. package/src/columns/{column_lazy.test.ts → data_column.test.ts} +19 -19
  98. package/src/columns/{column_lazy.ts → data_column.ts} +105 -67
  99. package/src/columns/derive_axis_values_labels.ts +4 -4
  100. package/src/columns/index.ts +2 -2
  101. package/src/columns/predicates.test.ts +124 -0
  102. package/src/columns/{expand_by_partition.test.ts → split_by_axes.test.ts} +29 -21
  103. package/src/columns/{expand_by_partition.ts → split_by_axes.ts} +22 -9
  104. package/src/columns/utils.ts +53 -48
  105. package/src/components/PlDataTable/columnResolver.test.ts +3 -3
  106. package/src/components/PlDataTable/createPlDataTable/createPTableDefV2.ts +3 -3
  107. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +2 -2
  108. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +2 -2
  109. package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +2 -2
  110. package/src/components/PlDataTable/createPlDataTable/utils.test.ts +3 -3
  111. package/src/components/PlDatasetSelector/enrichment_discovery.ts +2 -2
  112. package/dist/columns/column_lazy.cjs.map +0 -1
  113. package/dist/columns/column_lazy.d.ts +0 -137
  114. package/dist/columns/column_lazy.d.ts.map +0 -1
  115. package/dist/columns/column_lazy.js.map +0 -1
  116. package/dist/columns/expand_by_partition.cjs.map +0 -1
  117. package/dist/columns/expand_by_partition.d.ts.map +0 -1
  118. 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 expandByPartition} (or any consumer expecting the
18
+ * Pair with {@link splitByAxes} (or any consumer expecting the
19
19
  * `(axisId) => Record<axisValue, label>` shape).
20
20
  *
21
21
  * Skips:
22
- * - non-leaf recipes (only direct `ColumnLazy` data is read);
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 (!require_column_lazy.isColumnLazy(col)) return map;
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","isColumnLazy","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 { isColumnLazy } from \"./column_lazy\";\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 expandByPartition} (or any consumer expecting the\n * `(axisId) => Record<axisValue, label>` shape).\n *\n * Skips:\n * - non-leaf recipes (only direct `ColumnLazy` data is read);\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 (!isColumnLazy(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,oBAAAA,aAAa,GAAG,GAAG,OAAO;EAC/B,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"}
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 expandByPartition} (or any consumer expecting the
16
+ * Pair with {@link splitByAxes} (or any consumer expecting the
17
17
  * `(axisId) => Record<axisValue, label>` shape).
18
18
  *
19
19
  * Skips:
20
- * - non-leaf recipes (only direct `ColumnLazy` data is read);
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 expandByPartition} (or any consumer expecting the
18
+ * Pair with {@link splitByAxes} (or any consumer expecting the
19
19
  * `(axisId) => Record<axisValue, label>` shape).
20
20
  *
21
21
  * Skips:
22
- * - non-leaf recipes (only direct `ColumnLazy` data is read);
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 (!isColumnLazy(col)) return map;
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 { isColumnLazy } from \"./column_lazy\";\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 expandByPartition} (or any consumer expecting the\n * `(axisId) => Record<axisValue, label>` shape).\n *\n * Skips:\n * - non-leaf recipes (only direct `ColumnLazy` data is read);\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 (!isColumnLazy(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,aAAa,GAAG,GAAG,OAAO;EAC/B,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"}
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"}
@@ -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 require_column_lazy = require("./column_lazy.cjs");
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 = require_column_lazy.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;
@@ -1,15 +1,15 @@
1
1
  import { ColumnFieldStatus, ColumnRecipeId, ColumnResolutionStatus, SpecQuery } from "./column_recipes/types.js";
2
- import { ColumnAbsentError, ColumnLazy, ColumnLazyData, ColumnLazyId, ColumnLazyImpl, isColumnLazy } from "./column_lazy.js";
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, isColumnRecipe } from "./column_recipes/index.js";
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 { ExpandByPartitionOpts, SplitAxis, expandByPartition } from "./expand_by_partition.js";
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, getLeafColumnData, hasColumnData, hitQualifications, isLeafColumn, queriesQualifications } from "./utils.js";
15
- export { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, Column, ColumnAbsentError, ColumnDiscoveredRecipe, type ColumnFieldStatus, ColumnFilteredRecipe, ColumnLazy, ColumnLazyData, ColumnLazyId, ColumnLazyImpl, ColumnOption, ColumnOverriddenRecipe, ColumnRecipe, type ColumnRecipeId, type ColumnResolutionStatus, ColumnSource, ColumnsCollection, ColumnsCollectionDeps, ColumnsCollectionImpl, ColumnsProvider, ColumnsSource, ColumnsSourceShorthand, ExpandByPartitionOpts, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl, type SpecQuery, SplitAxis, _ctxProvidersCache, collectLinkerColumns, collectLinkerIds, deriveAxisValuesLabels, deriveColumnOptions, expandByPartition, getCtxProviders, getLeafColumnData, hasColumnData, hitQualifications, isColumn, isColumnLazy, isColumnProvider, isColumnRecipe, isColumnsCollection, isLeafColumn, queriesQualifications, toColumnProvider };
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 };
@@ -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, isColumnRecipe } from "./column_recipes/index.js";
4
+ import { ColumnRecipe } from "./column_recipes/index.js";
5
5
  import { ColumnOverriddenRecipe } from "./column_recipes/column_overrided_recipe.js";
6
- import { ColumnAbsentError, ColumnLazy, ColumnLazyImpl, isColumnLazy } from "./column_lazy.js";
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, getLeafColumnData, hasColumnData, hitQualifications, isLeafColumn, queriesQualifications } from "./utils.js";
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
- export { AccessorColumnsProvider, AccessorColumnsProviderImpl, ArrayColumnsProvider, Column, ColumnAbsentError, ColumnDiscoveredRecipe, ColumnFilteredRecipe, ColumnLazy, ColumnLazyImpl, ColumnOverriddenRecipe, ColumnRecipe, ColumnsCollection, ColumnsCollectionImpl, ColumnsProvider, ResultPoolColumnsProvider, ResultPoolColumnsProviderImpl, _ctxProvidersCache, collectLinkerColumns, collectLinkerIds, deriveAxisValuesLabels, deriveColumnOptions, expandByPartition, getCtxProviders, getLeafColumnData, hasColumnData, hitQualifications, isColumn, isColumnLazy, isColumnProvider, isColumnRecipe, isColumnsCollection, isLeafColumn, queriesQualifications, toColumnProvider };
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/expand_by_partition.ts
8
+ //#region src/columns/split_by_axes.ts
8
9
  const MAX_KEY_COMBINATIONS = 1e4;
9
10
  /**
10
- * Expand each input column along the requested partition axes into one
11
- * {@link ColumnRecipe} per Cartesian combination of unique partition values.
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 expandByPartition(inputs, splitAxes, opts) {
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.getLeafColumnData(inner);
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) => opts?.axisValuesLabels?.(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.expandByPartition = expandByPartition;
105
+ exports.splitByAxes = splitByAxes;
101
106
 
102
- //# sourceMappingURL=expand_by_partition.cjs.map
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/expand_by_partition.d.ts
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 ExpandByPartitionOpts {
11
- /** Resolve axis values to human-readable labels. */
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
- * Expand each input column along the requested partition axes into one
16
- * {@link ColumnRecipe} per Cartesian combination of unique partition values.
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 expandByPartition(inputs: Column[], splitAxes: SplitAxis[], opts?: ExpandByPartitionOpts): ColumnRecipe[] | undefined;
44
+ declare function splitByAxes(inputs: Column[], splitAxes: SplitAxis[], opts?: SplitByAxesOpts): ColumnRecipe[] | undefined;
35
45
  //#endregion
36
- export { ExpandByPartitionOpts, SplitAxis, expandByPartition };
37
- //# sourceMappingURL=expand_by_partition.d.ts.map
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 { getLeafColumnData } from "./utils.js";
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/expand_by_partition.ts
8
+ //#region src/columns/split_by_axes.ts
8
9
  const MAX_KEY_COMBINATIONS = 1e4;
9
10
  /**
10
- * Expand each input column along the requested partition axes into one
11
- * {@link ColumnRecipe} per Cartesian combination of unique partition values.
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 expandByPartition(inputs, splitAxes, opts) {
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 = getLeafColumnData(inner);
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) => opts?.axisValuesLabels?.(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 { expandByPartition };
105
+ export { splitByAxes };
101
106
 
102
- //# sourceMappingURL=expand_by_partition.js.map
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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"}
@@ -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 require_column_lazy = require("./column_lazy.cjs");
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 ColumnLazy} variant.
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 ColumnLazy} instances. Throws if any id fails to resolve —
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) => require_column_lazy.ColumnLazyImpl.fromId(id, opts) ?? (0, _milaboratories_helpers.throwError)(`materializeLinkers: linker ${id} not resolvable`));
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 ColumnLazy} through the ambient ctx) and ANDs `hasData()` across
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 lazy = require_column_lazy.ColumnLazyImpl.fromId(id, opts);
80
- if (lazy === void 0) return false;
81
- if (lazy.getDataStatus() !== "present") return false;
82
- if (!isLazyDataPresent(lazy.getData())) return false;
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 isLazyDataPresent(data) {
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
- * A recipe is a "leaf" (directly co-indexed on the anchor, reached without a
121
- * linker chain) iff its wrapper chain contains no {@link ColumnDiscoveredRecipe}.
120
+ * Whether the recipe reads exactly one data column — its own — rather than
121
+ * reaching through others.
122
122
  *
123
- * `Filtered` / `Overridden` over a bare leaf stay leaves; anything wrapping a
124
- * `Discovered` (e.g. `Overridden(Discovered(...))`) is linked. Use this — not an
125
- * `instanceof ColumnLazyImpl` check — to split direct vs. linker-joined columns,
126
- * since projections over a plain leaf are still direct.
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 isLeafColumn(recipe) {
129
- return findDiscovered(recipe) === void 0;
138
+ function hasSingleDataColumn(recipe) {
139
+ return recipe.getReferencedIds().length === 1;
130
140
  }
131
141
  /**
132
- * Data of the bare leaf a "leaf" recipe bottoms out at — reads the leaf-only
133
- * {@link ColumnLazy.getData} after walking the wrapper chain down via
134
- * {@link extractLeafColumn}. Returns `undefined` when the recipe is not a leaf (its
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
- function getLeafColumnData(recipe) {
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
- * Walk wrapper layers (Overridden, Filtered) down to the bare {@link ColumnLazy}
144
- * leaf the chain bottoms out at. Returns `undefined` if the chain reaches a
145
- * {@link ColumnDiscoveredRecipe} instead — i.e. the recipe is not a leaf
146
- * ({@link isLeafColumn} would return `false`). Mirror of {@link findDiscovered}.
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 extractLeafColumn(recipe) {
149
- let current = recipe;
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;