@platforma-sdk/model 1.80.17 → 1.81.1
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/PlDataTable/createPlDataTable/utils.cjs +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.js +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.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 +8 -8
- 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 +34 -3
- package/src/components/PlDataTable/createPlDataTable/utils.ts +4 -1
- 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
|
@@ -37,7 +37,7 @@ import { throwError } from "@milaboratories/helpers";
|
|
|
37
37
|
export class ColumnDiscoveredRecipe implements ColumnRecipe<ColumnDiscoveredId> {
|
|
38
38
|
/**
|
|
39
39
|
* Validate the key + resolve every referenced column via
|
|
40
|
-
* {@link
|
|
40
|
+
* {@link DataColumnRecipe.fromId} (which itself checks the leaf accessor reports
|
|
41
41
|
* `hasData()`). Returns `undefined` if the key is malformed or any
|
|
42
42
|
* referenced column is not yet spec-resolvable.
|
|
43
43
|
*
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type SpecQuery,
|
|
12
12
|
} from "@milaboratories/pl-model-common";
|
|
13
13
|
import type { GlobalCfgRenderCtx } from "../../render/internal";
|
|
14
|
+
import { type DataColumnRecipe, type ColumnData, isDataColumn } from "../data_column";
|
|
14
15
|
import type { ColumnFieldStatus, ColumnResolutionStatus } from "./types";
|
|
15
16
|
import { ColumnRecipe } from "./index";
|
|
16
17
|
import { Column } from "../column";
|
|
@@ -33,7 +34,7 @@ type NonOverriddenColumn = Column<Exclude<ColumnUniversalId, ColumnOverriddenId>
|
|
|
33
34
|
* This invariant matches the one enforced inside `unwrapOverrides` from
|
|
34
35
|
* pl-model-common: it explicitly throws on a nested override-wrap.
|
|
35
36
|
*/
|
|
36
|
-
export class ColumnOverriddenRecipe implements
|
|
37
|
+
export class ColumnOverriddenRecipe implements ColumnRecipe<ColumnOverriddenId> {
|
|
37
38
|
/**
|
|
38
39
|
* Wrap any recipe with overrides. If `inner` is already a
|
|
39
40
|
* {@link ColumnOverriddenRecipe}, merges `overrides` into the existing ones
|
|
@@ -42,12 +43,41 @@ export class ColumnOverriddenRecipe implements Column<ColumnOverriddenId> {
|
|
|
42
43
|
*/
|
|
43
44
|
static wrap(col: Column, overrides: SpecOverrides): ColumnOverriddenRecipe {
|
|
44
45
|
if (col instanceof ColumnOverriddenRecipe) {
|
|
45
|
-
return
|
|
46
|
+
return ColumnOverriddenRecipe.build(col.inner, mergeSpecOverrides(col.overrides, overrides));
|
|
46
47
|
}
|
|
47
48
|
// `inner` is not an Overridden wrap (the `instanceof` branch above handles
|
|
48
49
|
// that). Narrow the id union here so the constructor parameter stays
|
|
49
50
|
// honest with `ColumnOverriddenKey.source`.
|
|
50
|
-
return
|
|
51
|
+
return ColumnOverriddenRecipe.build(col as NonOverriddenColumn, overrides);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Pick the variant from the inner recipe: data-bearing inner →
|
|
56
|
+
* {@link DataColumnOverriddenRecipe}, otherwise the plain wrapper.
|
|
57
|
+
*
|
|
58
|
+
* The choice is **structural**, not a readiness check — it follows from
|
|
59
|
+
* which kind of recipe `inner` is, which in turn follows from the id alone
|
|
60
|
+
* (a bare `PObjectId` source is a leaf, anything else is not). So the same
|
|
61
|
+
* id always yields the same class, whether it was built via `withSpecs` or
|
|
62
|
+
* parsed from a string, and recipes stay value-objects that are equal iff
|
|
63
|
+
* their ids match.
|
|
64
|
+
*
|
|
65
|
+
* Re-deriving from `inner` on every build is also what keeps the merge path
|
|
66
|
+
* honest: `overridden.withSpecs(a).withSpecs(b)` cannot silently drop the
|
|
67
|
+
* data-bearing variant.
|
|
68
|
+
*
|
|
69
|
+
* Discriminated by method presence rather than `instanceof DataColumnImpl`
|
|
70
|
+
* to keep this module free of a runtime import cycle with `../data_column`.
|
|
71
|
+
* By the flat-merge invariant `inner` is never an Overridden, so the only
|
|
72
|
+
* recipe kind reaching here that carries `getData` is the leaf.
|
|
73
|
+
*/
|
|
74
|
+
private static build(
|
|
75
|
+
inner: NonOverriddenColumn,
|
|
76
|
+
overrides: SpecOverrides,
|
|
77
|
+
): ColumnOverriddenRecipe {
|
|
78
|
+
return isDataColumn(inner)
|
|
79
|
+
? new DataColumnOverriddenRecipe(inner, overrides)
|
|
80
|
+
: new ColumnOverriddenRecipe(inner, overrides);
|
|
51
81
|
}
|
|
52
82
|
|
|
53
83
|
/**
|
|
@@ -67,7 +97,7 @@ export class ColumnOverriddenRecipe implements Column<ColumnOverriddenId> {
|
|
|
67
97
|
private queryCache?: { readonly value: SpecQuery };
|
|
68
98
|
private dataStatusCache?: { readonly value: ColumnFieldStatus };
|
|
69
99
|
|
|
70
|
-
|
|
100
|
+
protected constructor(
|
|
71
101
|
private readonly inner: NonOverriddenColumn,
|
|
72
102
|
private readonly overrides: SpecOverrides,
|
|
73
103
|
) {
|
|
@@ -144,3 +174,27 @@ export class ColumnOverriddenRecipe implements Column<ColumnOverriddenId> {
|
|
|
144
174
|
return ColumnOverriddenRecipe.wrap(this, overrides);
|
|
145
175
|
}
|
|
146
176
|
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The variant produced when the wrapped recipe is itself data-bearing.
|
|
180
|
+
*
|
|
181
|
+
* Overrides are a pure spec patch — they never reshape the data — so the inner
|
|
182
|
+
* column's data stays consistent with this recipe's spec and is passed
|
|
183
|
+
* straight through. Which variant you get is decided once, at construction:
|
|
184
|
+
* see {@link build}.
|
|
185
|
+
*
|
|
186
|
+
* Not something callers name. Narrow with `hasReachableData(recipe)`, which
|
|
187
|
+
* yields the {@link DataColumnRecipe} interface.
|
|
188
|
+
*/
|
|
189
|
+
export class DataColumnOverriddenRecipe
|
|
190
|
+
extends ColumnOverriddenRecipe
|
|
191
|
+
implements DataColumnRecipe<ColumnOverriddenId>
|
|
192
|
+
{
|
|
193
|
+
/**
|
|
194
|
+
* Safe by construction: {@link build} only picks this class when the inner
|
|
195
|
+
* recipe exposes `getData`.
|
|
196
|
+
*/
|
|
197
|
+
getData(): ColumnData {
|
|
198
|
+
return (this.getInner() as DataColumnRecipe).getData();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -24,7 +24,7 @@ import { ColumnDiscoveredRecipe } from "./column_discovered_recipe";
|
|
|
24
24
|
import { ColumnOverriddenRecipe } from "./column_overrided_recipe";
|
|
25
25
|
import { ColumnFilteredRecipe } from "./column_filtered_recipe";
|
|
26
26
|
import { ColumnRecipe } from "./index";
|
|
27
|
-
import { ColumnAbsentError } from "../
|
|
27
|
+
import { ColumnAbsentError } from "../data_column";
|
|
28
28
|
import type { ColumnFieldStatus } from "./types";
|
|
29
29
|
import { installStubRegistry } from "../__test_helpers__/stub_registry";
|
|
30
30
|
import { throwError } from "@milaboratories/helpers";
|
|
@@ -581,7 +581,7 @@ describe("Wrapper getStatusByKey delegates to source", () => {
|
|
|
581
581
|
});
|
|
582
582
|
|
|
583
583
|
describe("ColumnRecipe.getStatus (top-level dispatcher)", () => {
|
|
584
|
-
test("routes bare PObjectId to
|
|
584
|
+
test("routes bare PObjectId to DataColumnImpl.getStatusById", () => {
|
|
585
585
|
setupCtx({ [baseLeaf]: stubSpec() });
|
|
586
586
|
expect(ColumnRecipe.getStatus(baseLeaf)).toBe("present");
|
|
587
587
|
});
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
isColumnFilteredKey,
|
|
9
9
|
} from "@milaboratories/pl-model-common";
|
|
10
10
|
import type { GlobalCfgRenderCtx } from "../../render/internal";
|
|
11
|
-
import {
|
|
11
|
+
import { DataColumn } from "../data_column";
|
|
12
12
|
import { ColumnDiscoveredRecipe } from "./column_discovered_recipe";
|
|
13
13
|
import { ColumnFilteredRecipe } from "./column_filtered_recipe";
|
|
14
14
|
import { ColumnOverriddenRecipe } from "./column_overrided_recipe";
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
} from "./types";
|
|
20
20
|
|
|
21
21
|
export type { ColumnFieldStatus, ColumnRecipeId, ColumnResolutionStatus, SpecQuery } from "./types";
|
|
22
|
-
export { ColumnAbsentError } from "../
|
|
22
|
+
export { ColumnAbsentError } from "../data_column";
|
|
23
23
|
export { ColumnDiscoveredRecipe } from "./column_discovered_recipe";
|
|
24
24
|
export { ColumnFilteredRecipe } from "./column_filtered_recipe";
|
|
25
25
|
export { ColumnOverriddenRecipe } from "./column_overrided_recipe";
|
|
@@ -38,7 +38,7 @@ export interface ColumnRecipe<
|
|
|
38
38
|
* concrete recipe variant based on the id's encoding and recurses on
|
|
39
39
|
* wrappers' inner `source`:
|
|
40
40
|
*
|
|
41
|
-
* - bare {@link PObjectId} (non-JSON) → `
|
|
41
|
+
* - bare {@link PObjectId} (non-JSON) → `DataColumnRecipe.fromId`
|
|
42
42
|
* - `ColumnDiscoveredKey` → {@link ColumnDiscoveredRecipe}
|
|
43
43
|
* - `ColumnOverriddenKey { source, specOverrides }` → recurse on `source`,
|
|
44
44
|
* then {@link ColumnOverriddenRecipe.wrap}
|
|
@@ -56,7 +56,7 @@ function ColumnRecipeBuild(
|
|
|
56
56
|
const parsed = parseColumnIdSafely(id);
|
|
57
57
|
|
|
58
58
|
if (isPObjectKey(parsed)) {
|
|
59
|
-
return
|
|
59
|
+
return DataColumn.fromId(id as PObjectId, opts);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (isColumnDiscoveredKey(parsed)) {
|
|
@@ -98,7 +98,7 @@ function ColumnRecipeGetStatus(
|
|
|
98
98
|
opts: { ctx?: GlobalCfgRenderCtx } = {},
|
|
99
99
|
): ColumnResolutionStatus {
|
|
100
100
|
const parsed = parseColumnIdSafely(id);
|
|
101
|
-
if (isPObjectKey(parsed)) return
|
|
101
|
+
if (isPObjectKey(parsed)) return DataColumn.getStatusById(id as PObjectId, opts);
|
|
102
102
|
if (isColumnDiscoveredKey(parsed)) return ColumnDiscoveredRecipe.getStatusByKey(parsed, opts);
|
|
103
103
|
if (isColumnOverriddenKey(parsed)) return ColumnOverriddenRecipe.getStatusByKey(parsed, opts);
|
|
104
104
|
if (isColumnFilteredKey(parsed)) return ColumnFilteredRecipe.getStatusByKey(parsed, opts);
|
|
@@ -110,18 +110,3 @@ export const ColumnRecipe: typeof ColumnRecipeBuild & {
|
|
|
110
110
|
} = Object.assign(ColumnRecipeBuild, {
|
|
111
111
|
getStatus: ColumnRecipeGetStatus,
|
|
112
112
|
});
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Type-guard for any recipe class — leaf {@link ColumnLazyImpl} or any of the
|
|
116
|
-
* wrapper recipes ({@link ColumnDiscoveredRecipe}, {@link ColumnFilteredRecipe},
|
|
117
|
-
* {@link ColumnOverriddenRecipe}). Use when a value may be a raw id, a `PColumn`,
|
|
118
|
-
* or a recipe and you want to branch on the recipe case.
|
|
119
|
-
*/
|
|
120
|
-
export function isColumnRecipe(value: unknown): value is ColumnRecipe {
|
|
121
|
-
return (
|
|
122
|
-
value instanceof ColumnLazyImpl ||
|
|
123
|
-
value instanceof ColumnDiscoveredRecipe ||
|
|
124
|
-
value instanceof ColumnFilteredRecipe ||
|
|
125
|
-
value instanceof ColumnOverriddenRecipe
|
|
126
|
-
);
|
|
127
|
-
}
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
type PColumnSpec,
|
|
7
7
|
type PObjectId,
|
|
8
8
|
} from "@milaboratories/pl-model-common";
|
|
9
|
-
import { ColumnAbsentError,
|
|
9
|
+
import { ColumnAbsentError, DataColumnImpl } from "./data_column";
|
|
10
10
|
import { _ctxProvidersCache } from "./column_providers";
|
|
11
11
|
import { installStubRegistry } from "./__test_helpers__/stub_registry";
|
|
12
12
|
|
|
13
13
|
// --- Ambient ctx mock ------------------------------------------------------
|
|
14
|
-
//
|
|
14
|
+
// DataColumnImpl constructor pulls `getCfgRenderCtx()` from globalThis. A minimal
|
|
15
15
|
// mock with empty index is enough — these tests don't exercise resolve paths.
|
|
16
16
|
|
|
17
17
|
const mockCtx = {
|
|
@@ -34,12 +34,12 @@ const baseLeaf = createLocalPObjectId(["main", "out"], "col-1");
|
|
|
34
34
|
const stubSpec = { kind: "PColumn", name: "stub" } as unknown as PColumnSpec;
|
|
35
35
|
|
|
36
36
|
function lazyOf(id: PObjectId, spec: PColumnSpec = stubSpec) {
|
|
37
|
-
return
|
|
37
|
+
return DataColumnImpl.fromColumn({ id, spec, data: undefined });
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// --- clone flattening -------------------------------------------------------
|
|
41
41
|
|
|
42
|
-
describe("
|
|
42
|
+
describe("DataColumnImpl.clone", () => {
|
|
43
43
|
test("two successive clones produce flat wrap (no nesting)", () => {
|
|
44
44
|
const c0 = lazyOf(baseLeaf);
|
|
45
45
|
const c1 = c0.withSpecs({
|
|
@@ -77,7 +77,7 @@ describe("ColumnLazy.clone", () => {
|
|
|
77
77
|
|
|
78
78
|
// --- spec() override application -------------------------------------------
|
|
79
79
|
|
|
80
|
-
describe("
|
|
80
|
+
describe("DataColumnImpl.spec — applySpecOverrides", () => {
|
|
81
81
|
test("base spec with no overrides returns readers.spec verbatim", () => {
|
|
82
82
|
const c = lazyOf(baseLeaf);
|
|
83
83
|
expect(c.getSpec()).toBe(stubSpec);
|
|
@@ -86,7 +86,7 @@ describe("ColumnLazy.spec — applySpecOverrides", () => {
|
|
|
86
86
|
test("fromId throws ColumnAbsentError when ctx has no handles", () => {
|
|
87
87
|
// Empty registry — `isFinal()` returns true vacuously, so the leaf is
|
|
88
88
|
// provably absent (no provider will ever supply it).
|
|
89
|
-
expect(() =>
|
|
89
|
+
expect(() => DataColumnImpl.fromId(baseLeaf)).toThrow(ColumnAbsentError);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
test("appends axes at indices past base.axesSpec.length", () => {
|
|
@@ -129,67 +129,67 @@ describe("ColumnLazy.spec — applySpecOverrides", () => {
|
|
|
129
129
|
|
|
130
130
|
// --- resolution status / absent throw --------------------------------------
|
|
131
131
|
|
|
132
|
-
describe("
|
|
132
|
+
describe("DataColumnImpl resolution: fromId / fromAccessor / getStatus", () => {
|
|
133
133
|
test("fromId returns undefined when registry is unfinalized and id not found", () => {
|
|
134
134
|
// `isFinal: false` → resolver can't tell yet → resolving → undefined.
|
|
135
135
|
installStubRegistry(mockCtx, {}, { isFinal: false });
|
|
136
|
-
expect(
|
|
136
|
+
expect(DataColumnImpl.fromId(baseLeaf)).toBeUndefined();
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
test("fromId throws ColumnAbsentError when leaf has no spec field on locked accessor", () => {
|
|
140
140
|
// Leaf entry present, no spec field, accessor locked → absent forever.
|
|
141
141
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: true } });
|
|
142
|
-
expect(() =>
|
|
142
|
+
expect(() => DataColumnImpl.fromId(baseLeaf)).toThrow(ColumnAbsentError);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
test("fromId returns undefined when leaf has no spec field on unlocked accessor", () => {
|
|
146
146
|
// Leaf entry present, no spec field, accessor unlocked → spec may still arrive.
|
|
147
147
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: false } });
|
|
148
|
-
expect(
|
|
148
|
+
expect(DataColumnImpl.fromId(baseLeaf)).toBeUndefined();
|
|
149
149
|
});
|
|
150
150
|
|
|
151
151
|
test("fromId returns undefined when spec accessor exists but hasData is false", () => {
|
|
152
152
|
// Spec resource present, bytes not yet written — transient resolving.
|
|
153
153
|
installStubRegistry(mockCtx, { [baseLeaf]: { spec: stubSpec, specHasData: false } });
|
|
154
|
-
expect(
|
|
154
|
+
expect(DataColumnImpl.fromId(baseLeaf)).toBeUndefined();
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
test("fromAccessor throws ColumnAbsentError when accessor is locked without spec", () => {
|
|
158
158
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: true } });
|
|
159
159
|
const entry = pluckLeafEntry(baseLeaf);
|
|
160
|
-
expect(() =>
|
|
160
|
+
expect(() => DataColumnImpl.fromAccessor(entry)).toThrow(ColumnAbsentError);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
test("fromAccessor returns undefined when accessor is unlocked without spec", () => {
|
|
164
164
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: false } });
|
|
165
165
|
const entry = pluckLeafEntry(baseLeaf);
|
|
166
|
-
expect(
|
|
166
|
+
expect(DataColumnImpl.fromAccessor(entry)).toBeUndefined();
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
test("getStatusById returns 'absent' / 'resolving' / 'present' across configurations", () => {
|
|
170
170
|
// present — spec with data on a locked, populated leaf.
|
|
171
171
|
installStubRegistry(mockCtx, { [baseLeaf]: stubSpec });
|
|
172
|
-
expect(
|
|
172
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("present");
|
|
173
173
|
|
|
174
174
|
// resolving — same leaf id, spec bytes not yet written.
|
|
175
175
|
installStubRegistry(mockCtx, { [baseLeaf]: { spec: stubSpec, specHasData: false } });
|
|
176
|
-
expect(
|
|
176
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("resolving");
|
|
177
177
|
|
|
178
178
|
// resolving — leaf entry exists but spec field missing on an unlocked accessor.
|
|
179
179
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: false } });
|
|
180
|
-
expect(
|
|
180
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("resolving");
|
|
181
181
|
|
|
182
182
|
// absent — leaf entry exists with no spec field on a locked accessor.
|
|
183
183
|
installStubRegistry(mockCtx, { [baseLeaf]: { accessorLocked: true } });
|
|
184
|
-
expect(
|
|
184
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("absent");
|
|
185
185
|
|
|
186
186
|
// absent — id not in any provider and registry is final.
|
|
187
187
|
installStubRegistry(mockCtx, {}, { isFinal: true });
|
|
188
|
-
expect(
|
|
188
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("absent");
|
|
189
189
|
|
|
190
190
|
// resolving — id not in any provider but registry still enumerating.
|
|
191
191
|
installStubRegistry(mockCtx, {}, { isFinal: false });
|
|
192
|
-
expect(
|
|
192
|
+
expect(DataColumnImpl.getStatusById(baseLeaf)).toBe("resolving");
|
|
193
193
|
});
|
|
194
194
|
});
|
|
195
195
|
|
|
@@ -20,14 +20,37 @@ import { TreeNodeAccessor } from "../render";
|
|
|
20
20
|
import type {
|
|
21
21
|
ColumnFieldStatus,
|
|
22
22
|
ColumnRecipe,
|
|
23
|
+
ColumnRecipeId,
|
|
23
24
|
ColumnResolutionStatus,
|
|
24
25
|
} from "./column_recipes/types";
|
|
25
26
|
import { ColumnOverriddenRecipe } from "./column_recipes/column_overrided_recipe";
|
|
26
27
|
|
|
27
|
-
export type
|
|
28
|
-
export type
|
|
28
|
+
export type DataColumnId = PObjectId;
|
|
29
|
+
export type ColumnData = undefined | PColumnDataUniversal;
|
|
29
30
|
export type { ColumnFieldStatus, ColumnResolutionStatus } from "./column_recipes/types";
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* A {@link ColumnRecipe} that can be read directly in the sandbox: its
|
|
34
|
+
* {@link getData} is guaranteed to be consistent with {@link getSpec}.
|
|
35
|
+
*
|
|
36
|
+
* This is a *capability*, not a class. Only two recipe shapes carry it — a
|
|
37
|
+
* bare leaf and a spec-override over a bare leaf — because those are the only
|
|
38
|
+
* ones whose data still matches their spec. An axis-filtered recipe drops axes
|
|
39
|
+
* from its spec while the underlying data keeps them, and a discovered recipe
|
|
40
|
+
* only materialises after a join; neither can be read here, so neither
|
|
41
|
+
* implements this interface.
|
|
42
|
+
*
|
|
43
|
+
* Narrow to it with `hasReachableData(recipe)` rather than testing for a concrete
|
|
44
|
+
* class — which recipe classes exist is an implementation detail behind
|
|
45
|
+
* `recipe.id`.
|
|
46
|
+
*/
|
|
47
|
+
export interface DataColumnRecipe<
|
|
48
|
+
ID extends ColumnRecipeId = ColumnRecipeId,
|
|
49
|
+
> extends ColumnRecipe<ID> {
|
|
50
|
+
/** Column data, consistent with {@link ColumnRecipe.getSpec}. */
|
|
51
|
+
getData(): ColumnData;
|
|
52
|
+
}
|
|
53
|
+
|
|
31
54
|
/**
|
|
32
55
|
* Thrown by leaf-recipe factories when the requested column is provably
|
|
33
56
|
* absent in the active render ctx — i.e. every relevant accessor reports
|
|
@@ -47,22 +70,24 @@ export class ColumnAbsentError extends Error {
|
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
73
|
+
* The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare
|
|
74
|
+
* {@link PObjectId} and whose readers are bound to a single tree-accessor
|
|
75
|
+
* leaf. Layered encodings (Overridden / Discovered / Filtered) are reified
|
|
76
|
+
* through their dedicated recipe classes and reference leaf columns by id.
|
|
77
|
+
*
|
|
78
|
+
* Internal — consumers hold the {@link DataColumnRecipe} interface and construct
|
|
79
|
+
* through the {@link DataColumnRecipe} dispatcher.
|
|
55
80
|
*/
|
|
56
|
-
export class
|
|
81
|
+
export class DataColumnImpl implements DataColumnRecipe<PObjectId> {
|
|
57
82
|
private specCache?: { readonly value: PColumnSpec };
|
|
58
|
-
private dataCache?: { readonly value:
|
|
83
|
+
private dataCache?: { readonly value: ColumnData };
|
|
59
84
|
private dataStatusCache?: { readonly value: ColumnFieldStatus };
|
|
60
85
|
|
|
61
86
|
private constructor(
|
|
62
87
|
public readonly id: PObjectId,
|
|
63
88
|
private readonly options: {
|
|
64
89
|
getSpec: () => PColumnSpec;
|
|
65
|
-
getData: () =>
|
|
90
|
+
getData: () => ColumnData;
|
|
66
91
|
getDataStatus: () => ColumnFieldStatus;
|
|
67
92
|
},
|
|
68
93
|
) {}
|
|
@@ -84,8 +109,7 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
84
109
|
return { type: "column", column: this.id } as SpecQuery;
|
|
85
110
|
}
|
|
86
111
|
|
|
87
|
-
|
|
88
|
-
getData(): ColumnLazyData {
|
|
112
|
+
getData(): ColumnData {
|
|
89
113
|
if (this.dataCache === undefined) this.dataCache = { value: this.options.getData() };
|
|
90
114
|
return this.dataCache.value;
|
|
91
115
|
}
|
|
@@ -99,7 +123,7 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
99
123
|
|
|
100
124
|
/**
|
|
101
125
|
* Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
|
|
102
|
-
* this leaf.
|
|
126
|
+
* this leaf. The leaf itself stays bare (id remains a plain PObjectId);
|
|
103
127
|
* layering lives entirely in the recipe wrappers.
|
|
104
128
|
*/
|
|
105
129
|
withSpecs(overrides: SpecOverrides): ColumnRecipe {
|
|
@@ -113,7 +137,10 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
113
137
|
* and the column did not appear — the column will not exist in this ctx.
|
|
114
138
|
* Data and dataStatus stay lazy.
|
|
115
139
|
*/
|
|
116
|
-
static fromId(
|
|
140
|
+
static fromId(
|
|
141
|
+
id: PObjectId,
|
|
142
|
+
{ ctx }: { ctx?: GlobalCfgRenderCtx } = {},
|
|
143
|
+
): undefined | DataColumnRecipe<PObjectId> {
|
|
117
144
|
const registry = new ColumnRegistry(getCtxProviders({ ctx }));
|
|
118
145
|
const leaf = registry.resolve(id);
|
|
119
146
|
if (isNil(leaf)) {
|
|
@@ -126,7 +153,7 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
126
153
|
return undefined;
|
|
127
154
|
}
|
|
128
155
|
if (!spec.hasData()) return undefined;
|
|
129
|
-
return new
|
|
156
|
+
return new DataColumnImpl(id, {
|
|
130
157
|
getSpec: () => spec.getDataAsJson<PColumnSpec>(),
|
|
131
158
|
getData: () => readDataAccessor(leaf),
|
|
132
159
|
getDataStatus: () => readDataStatus(leaf),
|
|
@@ -134,8 +161,8 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
134
161
|
}
|
|
135
162
|
|
|
136
163
|
/** {@link PlRef} wrapper over {@link fromId}. */
|
|
137
|
-
static fromPlRef(ref: PlRef): undefined |
|
|
138
|
-
return
|
|
164
|
+
static fromPlRef(ref: PlRef): undefined | DataColumnRecipe<PObjectId> {
|
|
165
|
+
return DataColumnImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));
|
|
139
166
|
}
|
|
140
167
|
|
|
141
168
|
/**
|
|
@@ -143,14 +170,14 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
143
170
|
* Throws {@link ColumnAbsentError} if the leaf has no spec field and its
|
|
144
171
|
* accessor is `inputsLocked`. Returns `undefined` while still resolving.
|
|
145
172
|
*/
|
|
146
|
-
static fromAccessor(entry: LeafEntry<TreeNodeAccessor>): undefined |
|
|
173
|
+
static fromAccessor(entry: LeafEntry<TreeNodeAccessor>): undefined | DataColumnRecipe<PObjectId> {
|
|
147
174
|
const spec = readSpecAccessor(entry);
|
|
148
175
|
if (isNil(spec)) {
|
|
149
176
|
if (entry.accessor.getInputsLocked()) throw new ColumnAbsentError(entry.id);
|
|
150
177
|
return undefined;
|
|
151
178
|
}
|
|
152
179
|
if (!spec.hasData()) return undefined;
|
|
153
|
-
return new
|
|
180
|
+
return new DataColumnImpl(entry.id, {
|
|
154
181
|
getSpec: () => spec.getDataAsJson<PColumnSpec>(),
|
|
155
182
|
getData: () => readDataAccessor(entry),
|
|
156
183
|
getDataStatus: () => readDataStatus(entry),
|
|
@@ -159,13 +186,20 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
159
186
|
|
|
160
187
|
/**
|
|
161
188
|
* Wrap a materialised {@link PColumn}. If the input is already a
|
|
162
|
-
* {@link
|
|
189
|
+
* {@link DataColumnRecipe} leaf it is returned as-is.
|
|
163
190
|
*/
|
|
164
|
-
static fromColumn(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
191
|
+
static fromColumn(
|
|
192
|
+
column: PColumn<ColumnData> | DataColumnRecipe<PObjectId>,
|
|
193
|
+
): DataColumnRecipe<PObjectId> {
|
|
194
|
+
if (column instanceof DataColumnImpl) return column;
|
|
195
|
+
// `DataColumnRecipe` is an interface, so `instanceof` above does not remove it
|
|
196
|
+
// from the union. The only implementation carrying a bare `PObjectId` is
|
|
197
|
+
// `DataColumnImpl` (wrappers expose `ColumnUniversalId`), so anything
|
|
198
|
+
// reaching here is a materialised `PColumn`.
|
|
199
|
+
const pColumn = column as PColumn<ColumnData>;
|
|
200
|
+
return new DataColumnImpl(pColumn.id, {
|
|
201
|
+
getSpec: () => pColumn.spec,
|
|
202
|
+
getData: () => pColumn.data,
|
|
169
203
|
getDataStatus: () => "present",
|
|
170
204
|
});
|
|
171
205
|
}
|
|
@@ -191,7 +225,7 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
191
225
|
ref: PlRef,
|
|
192
226
|
opts: { ctx?: GlobalCfgRenderCtx } = {},
|
|
193
227
|
): ColumnResolutionStatus {
|
|
194
|
-
return
|
|
228
|
+
return DataColumnImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);
|
|
195
229
|
}
|
|
196
230
|
|
|
197
231
|
/** No registry — reads straight off the entry's accessor. */
|
|
@@ -200,67 +234,71 @@ export class ColumnLazyImpl implements ColumnRecipe<PObjectId> {
|
|
|
200
234
|
}
|
|
201
235
|
}
|
|
202
236
|
|
|
203
|
-
/**
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
/** Anything the {@link DataColumnRecipe} dispatcher can build a leaf from. */
|
|
238
|
+
export type DataColumnSource =
|
|
239
|
+
| PObjectId
|
|
240
|
+
| PlRef
|
|
241
|
+
| LeafEntry<TreeNodeAccessor>
|
|
242
|
+
| PColumn<ColumnData>
|
|
243
|
+
| DataColumnRecipe<PObjectId>;
|
|
209
244
|
|
|
210
245
|
/**
|
|
211
|
-
* Unified dispatcher — picks the right `
|
|
246
|
+
* Unified dispatcher — picks the right `DataColumnImpl.fromX` by source
|
|
212
247
|
* shape. For ambiguous inputs callers can still use the explicit factories
|
|
213
|
-
* (also attached as properties: `
|
|
248
|
+
* (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,
|
|
214
249
|
* `.fromAccessor`, `.fromColumn`).
|
|
215
250
|
*/
|
|
216
|
-
function
|
|
217
|
-
source:
|
|
251
|
+
function DataColumnDispatch(
|
|
252
|
+
source: DataColumnSource,
|
|
218
253
|
opts: { ctx?: GlobalCfgRenderCtx } = {},
|
|
219
|
-
): undefined |
|
|
220
|
-
if (typeof source === "string") return
|
|
221
|
-
if (source instanceof
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
254
|
+
): undefined | DataColumnRecipe<PObjectId> {
|
|
255
|
+
if (typeof source === "string") return DataColumnImpl.fromId(source, opts);
|
|
256
|
+
if (source instanceof DataColumnImpl) return source;
|
|
257
|
+
// `DataColumnRecipe` is an interface — `instanceof` above cannot remove it from
|
|
258
|
+
// the union, and only `DataColumnImpl` implements it with a bare id.
|
|
259
|
+
const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;
|
|
260
|
+
if ("accessor" in rest) return DataColumnImpl.fromAccessor(rest);
|
|
261
|
+
if (isPlRef(rest)) return DataColumnImpl.fromPlRef(rest);
|
|
262
|
+
if (isPColumn(rest)) return DataColumnImpl.fromColumn(rest);
|
|
263
|
+
throw new Error("DataColumn: unknown source shape");
|
|
226
264
|
}
|
|
227
265
|
|
|
228
266
|
/**
|
|
229
|
-
* Polymorphic counterpart to {@link
|
|
267
|
+
* Polymorphic counterpart to {@link DataColumnDispatch}: returns the
|
|
230
268
|
* {@link ColumnResolutionStatus} for any factory input without constructing
|
|
231
269
|
* the recipe. For already-materialised sources ({@link PColumn} value,
|
|
232
|
-
* existing {@link
|
|
270
|
+
* existing {@link DataColumnRecipe}) status is `present` by construction.
|
|
233
271
|
*/
|
|
234
|
-
function
|
|
235
|
-
source:
|
|
272
|
+
function DataColumnGetStatus(
|
|
273
|
+
source: DataColumnSource,
|
|
236
274
|
opts: { ctx?: GlobalCfgRenderCtx } = {},
|
|
237
275
|
): ColumnResolutionStatus {
|
|
238
|
-
if (typeof source === "string") return
|
|
239
|
-
if (source instanceof
|
|
240
|
-
|
|
241
|
-
if (
|
|
242
|
-
if (
|
|
243
|
-
|
|
276
|
+
if (typeof source === "string") return DataColumnImpl.getStatusById(source, opts);
|
|
277
|
+
if (source instanceof DataColumnImpl) return "present";
|
|
278
|
+
const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;
|
|
279
|
+
if ("accessor" in rest) return DataColumnImpl.getStatusByAccessor(rest);
|
|
280
|
+
if (isPlRef(rest)) return DataColumnImpl.getStatusByPlRef(rest, opts);
|
|
281
|
+
if (isPColumn(rest)) return "present";
|
|
282
|
+
throw new Error("DataColumn.getStatus: unknown source shape");
|
|
244
283
|
}
|
|
245
284
|
|
|
246
|
-
export const
|
|
247
|
-
fromId:
|
|
248
|
-
fromPlRef:
|
|
249
|
-
fromAccessor:
|
|
250
|
-
fromColumn:
|
|
251
|
-
getStatus:
|
|
252
|
-
getStatusById:
|
|
253
|
-
getStatusByPlRef:
|
|
254
|
-
getStatusByAccessor:
|
|
285
|
+
export const DataColumn = Object.assign(DataColumnDispatch, {
|
|
286
|
+
fromId: DataColumnImpl.fromId,
|
|
287
|
+
fromPlRef: DataColumnImpl.fromPlRef,
|
|
288
|
+
fromAccessor: DataColumnImpl.fromAccessor,
|
|
289
|
+
fromColumn: DataColumnImpl.fromColumn,
|
|
290
|
+
getStatus: DataColumnGetStatus,
|
|
291
|
+
getStatusById: DataColumnImpl.getStatusById,
|
|
292
|
+
getStatusByPlRef: DataColumnImpl.getStatusByPlRef,
|
|
293
|
+
getStatusByAccessor: DataColumnImpl.getStatusByAccessor,
|
|
255
294
|
});
|
|
256
295
|
|
|
257
296
|
/**
|
|
258
|
-
* Type-guard narrowing to
|
|
259
|
-
*
|
|
260
|
-
* with statics, not the class, so `instanceof` requires the impl symbol.
|
|
297
|
+
* Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a
|
|
298
|
+
* plain {@link PObjectId}.
|
|
261
299
|
*/
|
|
262
|
-
export function
|
|
263
|
-
return value instanceof
|
|
300
|
+
export function isDataColumn(value: unknown): value is DataColumnRecipe<PObjectId> {
|
|
301
|
+
return value instanceof DataColumnImpl;
|
|
264
302
|
}
|
|
265
303
|
|
|
266
304
|
const readSpecAccessor = memoizeByEntry(
|
|
@@ -4,7 +4,7 @@ import type { ColumnsSource } from "./column_providers";
|
|
|
4
4
|
import { ColumnsCollection, isColumnsCollection } from "./columns_collection";
|
|
5
5
|
import type { GlobalCfgRenderCtx } from "../render/internal";
|
|
6
6
|
import { TreeNodeAccessor } from "../render";
|
|
7
|
-
import {
|
|
7
|
+
import { hasReachableData } from "./utils";
|
|
8
8
|
|
|
9
9
|
const RT_JSON = "PColumnData/Json";
|
|
10
10
|
const RT_JSON_PARTITIONED = "PColumnData/JsonPartitioned";
|
|
@@ -18,11 +18,11 @@ const RT_JSON_PARTITIONED = "PColumnData/JsonPartitioned";
|
|
|
18
18
|
* column-access mechanism (filtered {@link ColumnsCollection}) instead of
|
|
19
19
|
* walking the raw result pool.
|
|
20
20
|
*
|
|
21
|
-
* Pair with {@link
|
|
21
|
+
* Pair with {@link splitByAxes} (or any consumer expecting the
|
|
22
22
|
* `(axisId) => Record<axisValue, label>` shape).
|
|
23
23
|
*
|
|
24
24
|
* Skips:
|
|
25
|
-
* -
|
|
25
|
+
* - recipes whose data is not directly readable (see `hasReachableData`);
|
|
26
26
|
* - label columns whose `axesSpec.length !== 1`;
|
|
27
27
|
* - label columns whose data resource type isn't `PColumnData/Json` /
|
|
28
28
|
* `PColumnData/JsonPartitioned`.
|
|
@@ -43,7 +43,7 @@ export function deriveAxisValuesLabels(
|
|
|
43
43
|
.getColumns();
|
|
44
44
|
|
|
45
45
|
const byAxis = labelCols.reduce<Map<string, Record<string | number, string>>>((map, col) => {
|
|
46
|
-
if (!
|
|
46
|
+
if (!hasReachableData(col)) return map;
|
|
47
47
|
const spec = col.getSpec();
|
|
48
48
|
if (spec.axesSpec.length !== 1) return map;
|
|
49
49
|
|
package/src/columns/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export * from "./column_providers";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./split_by_axes";
|
|
3
3
|
export * from "./derive_axis_values_labels";
|
|
4
4
|
export * from "./columns_collection";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./data_column";
|
|
6
6
|
export * from "./column_recipes";
|
|
7
7
|
export * from "./column";
|
|
8
8
|
export * from "./utils";
|