@platforma-sdk/model 1.27.10 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +745 -602
- package/dist/index.mjs.map +1 -1
- package/dist/render/api.d.ts +19 -29
- package/dist/render/api.d.ts.map +1 -1
- package/dist/render/util/column_collection.d.ts +54 -0
- package/dist/render/util/column_collection.d.ts.map +1 -0
- package/dist/render/util/index.d.ts +1 -0
- package/dist/render/util/index.d.ts.map +1 -1
- package/dist/render/util/pcolumn_data.d.ts +11 -2
- package/dist/render/util/pcolumn_data.d.ts.map +1 -1
- package/dist/render/util/split_selectors.d.ts +26 -0
- package/dist/render/util/split_selectors.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/render/api.ts +94 -296
- package/src/render/util/column_collection.ts +421 -0
- package/src/render/util/index.ts +1 -0
- package/src/render/util/pcolumn_data.ts +62 -4
- package/src/render/util/split_selectors.ts +29 -0
- package/dist/render/split_selectors.d.ts +0 -14
- package/dist/render/split_selectors.d.ts.map +0 -1
- package/src/render/split_selectors.ts +0 -15
package/src/render/api.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AnyFunction,
|
|
2
3
|
AxisId,
|
|
4
|
+
DataInfo,
|
|
3
5
|
Option,
|
|
4
6
|
PColumn,
|
|
5
7
|
PColumnSelector,
|
|
@@ -8,6 +10,7 @@ import type {
|
|
|
8
10
|
PFrameDef,
|
|
9
11
|
PFrameHandle,
|
|
10
12
|
PObject,
|
|
13
|
+
PObjectId,
|
|
11
14
|
PObjectSpec,
|
|
12
15
|
PSpecPredicate,
|
|
13
16
|
PTableDef,
|
|
@@ -16,28 +19,18 @@ import type {
|
|
|
16
19
|
PTableSorting,
|
|
17
20
|
PlRef,
|
|
18
21
|
ResultCollection,
|
|
19
|
-
ValueOrError,
|
|
20
|
-
AxisFilter,
|
|
21
|
-
PValue,
|
|
22
22
|
SUniversalPColumnId,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
BinaryPartitionedDataInfoEntries,
|
|
26
|
-
JsonPartitionedDataInfoEntries,
|
|
27
|
-
PObjectId } from '@milaboratories/pl-model-common';
|
|
23
|
+
ValueOrError,
|
|
24
|
+
} from '@milaboratories/pl-model-common';
|
|
28
25
|
import {
|
|
29
|
-
mapDataInfo,
|
|
30
|
-
entriesToDataInfo,
|
|
31
|
-
isDataInfo,
|
|
32
26
|
AnchoredIdDeriver,
|
|
33
|
-
getAxisId,
|
|
34
|
-
resolveAnchors,
|
|
35
|
-
canonicalizeAxisId,
|
|
36
27
|
ensurePColumn,
|
|
37
28
|
extractAllColumns,
|
|
29
|
+
isDataInfo,
|
|
38
30
|
isPColumn,
|
|
39
31
|
isPColumnSpec,
|
|
40
32
|
isPlRef,
|
|
33
|
+
mapDataInfo,
|
|
41
34
|
mapPObjectData,
|
|
42
35
|
mapPTableDef,
|
|
43
36
|
mapValueInVOE,
|
|
@@ -50,11 +43,10 @@ import type { FutureRef } from './future';
|
|
|
50
43
|
import type { AccessorHandle, GlobalCfgRenderCtx } from './internal';
|
|
51
44
|
import { MainAccessorName, StagingAccessorName } from './internal';
|
|
52
45
|
import type { LabelDerivationOps } from './util/label';
|
|
46
|
+
import { PColumnCollection, type AxisLabelProvider, type ColumnProvider } from './util/column_collection';
|
|
53
47
|
import { deriveLabels } from './util/label';
|
|
54
|
-
import type { APColumnSelectorWithSplit } from './split_selectors';
|
|
55
|
-
import
|
|
56
|
-
import type { TraceEntry } from './util/label';
|
|
57
|
-
import { filterDataInfoEntries } from './util/axis_filtering';
|
|
48
|
+
import type { APColumnSelectorWithSplit } from './util/split_selectors';
|
|
49
|
+
import canonicalize from 'canonicalize';
|
|
58
50
|
|
|
59
51
|
/**
|
|
60
52
|
* Helper function to match domain objects
|
|
@@ -91,56 +83,12 @@ PColumn<PColumnValues | AccessorHandle | DataInfo<AccessorHandle>> {
|
|
|
91
83
|
});
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
/**
|
|
95
|
-
* Describes a single filter applied due to a split axis.
|
|
96
|
-
*/
|
|
97
|
-
export type AxisFilterInfo = {
|
|
98
|
-
axisIdx: number;
|
|
99
|
-
axisId: AxisId;
|
|
100
|
-
value: PValue;
|
|
101
|
-
label: string;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Represents a column specification with potential split axis filtering information
|
|
106
|
-
* used in canonical options generation.
|
|
107
|
-
*/
|
|
108
|
-
export type UniversalPColumnEntry = {
|
|
109
|
-
id: SUniversalPColumnId;
|
|
110
|
-
obj: PColumnSpec;
|
|
111
|
-
ref: PlRef;
|
|
112
|
-
axisFilters?: AxisFilterInfo[];
|
|
113
|
-
label: string;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Converts an array of SplitAxisFilter objects into an array of TraceEntry objects
|
|
118
|
-
* suitable for label generation.
|
|
119
|
-
*/
|
|
120
|
-
function splitFiltersToTrace(splitFilters?: AxisFilterInfo[]): TraceEntry[] | undefined {
|
|
121
|
-
if (!splitFilters) return undefined;
|
|
122
|
-
return splitFilters.map((filter) => ({
|
|
123
|
-
type: `split:${canonicalizeAxisId(filter.axisId)}`,
|
|
124
|
-
label: filter.label,
|
|
125
|
-
importance: 1_000_000, // High importance for split filters in labels
|
|
126
|
-
}));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Converts an array of SplitAxisFilter objects into an array of AxisFilter tuples
|
|
131
|
-
* suitable for deriving anchored IDs.
|
|
132
|
-
*/
|
|
133
|
-
function splitFiltersToAxisFilter(splitFilters?: AxisFilterInfo[]): AxisFilter[] | undefined {
|
|
134
|
-
if (!splitFilters) return undefined;
|
|
135
|
-
return splitFilters.map((filter) => [filter.axisIdx, filter.value]);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
86
|
type UniversalPColumnOpts = {
|
|
139
87
|
labelOps?: LabelDerivationOps;
|
|
140
88
|
dontWaitAllData?: boolean;
|
|
141
89
|
};
|
|
142
90
|
|
|
143
|
-
export class ResultPool {
|
|
91
|
+
export class ResultPool implements ColumnProvider, AxisLabelProvider {
|
|
144
92
|
private readonly ctx: GlobalCfgRenderCtx = getCfgRenderCtx();
|
|
145
93
|
|
|
146
94
|
/**
|
|
@@ -170,165 +118,20 @@ export class ResultPool {
|
|
|
170
118
|
}));
|
|
171
119
|
}
|
|
172
120
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* anchors and selectors.
|
|
176
|
-
*/
|
|
177
|
-
public getUniversalPColumnEntries(
|
|
178
|
-
anchorsOrCtx: AnchoredIdDeriver | Record<string, PColumnSpec | PlRef>,
|
|
179
|
-
predicateOrSelectors: ((spec: PColumnSpec) => boolean) | APColumnSelectorWithSplit | APColumnSelectorWithSplit[],
|
|
180
|
-
opts?: UniversalPColumnOpts,
|
|
181
|
-
): UniversalPColumnEntry[] | undefined {
|
|
182
|
-
// Handle PlRef objects by resolving them to PColumnSpec
|
|
121
|
+
public resolveAnchorCtx(anchorsOrCtx: AnchoredIdDeriver | Record<string, PColumnSpec | PlRef>): AnchoredIdDeriver | undefined {
|
|
122
|
+
if (anchorsOrCtx instanceof AnchoredIdDeriver) return anchorsOrCtx;
|
|
183
123
|
const resolvedAnchors: Record<string, PColumnSpec> = {};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return undefined;
|
|
191
|
-
resolvedAnchors[key] = resolvedSpec;
|
|
192
|
-
} else {
|
|
193
|
-
// It's already a PColumnSpec
|
|
194
|
-
resolvedAnchors[key] = value;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const selectorsArray = typeof predicateOrSelectors === 'function'
|
|
200
|
-
? [predicateOrSelectors]
|
|
201
|
-
: Array.isArray(predicateOrSelectors)
|
|
202
|
-
? predicateOrSelectors
|
|
203
|
-
: [predicateOrSelectors];
|
|
204
|
-
|
|
205
|
-
const anchorIdDeriver = anchorsOrCtx instanceof AnchoredIdDeriver
|
|
206
|
-
? anchorsOrCtx
|
|
207
|
-
: new AnchoredIdDeriver(resolvedAnchors);
|
|
208
|
-
|
|
209
|
-
const result: Omit<UniversalPColumnEntry, 'id' | 'label'>[] = [];
|
|
210
|
-
|
|
211
|
-
// Process each selector individually
|
|
212
|
-
for (const selector of selectorsArray) {
|
|
213
|
-
// Create predicate for this specific selector
|
|
214
|
-
const predicate = typeof selector === 'function'
|
|
215
|
-
? selector
|
|
216
|
-
: selectorsToPredicate(resolveAnchors(resolvedAnchors, selector));
|
|
217
|
-
|
|
218
|
-
// Filter specs based on this specific predicate
|
|
219
|
-
const filtered = this.getSpecs().entries.filter(({ obj: spec }) => {
|
|
220
|
-
if (!isPColumnSpec(spec)) return false;
|
|
221
|
-
return predicate(spec);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
if (filtered.length === 0)
|
|
225
|
-
continue;
|
|
226
|
-
|
|
227
|
-
// Check if this selector has any split axes
|
|
228
|
-
const splitAxisIdxs = typeof selector === 'object'
|
|
229
|
-
&& 'axes' in selector
|
|
230
|
-
&& selector.axes !== undefined
|
|
231
|
-
&& selector.partialAxesMatch === undefined
|
|
232
|
-
? selector.axes
|
|
233
|
-
.map((axis, index) => ('split' in axis && axis.split === true) ? index : -1)
|
|
234
|
-
.filter((index) => index !== -1)
|
|
235
|
-
: [];
|
|
236
|
-
splitAxisIdxs.sort((a, b) => a - b);
|
|
237
|
-
|
|
238
|
-
if (splitAxisIdxs.length > 0) { // Handle split axes
|
|
239
|
-
const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1]; // Last one is max since they're sorted
|
|
240
|
-
|
|
241
|
-
for (const { ref, obj: spec } of filtered) {
|
|
242
|
-
if (!isPColumnSpec(spec)) throw new Error(`Assertion failed: expected PColumnSpec, got ${spec.kind}`);
|
|
243
|
-
|
|
244
|
-
const columnData = this.getDataByRef(ref);
|
|
245
|
-
if (!columnData) {
|
|
246
|
-
if (opts?.dontWaitAllData) continue;
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
if (!isPColumn(columnData)) throw new Error(`Assertion failed: expected PColumn, got ${columnData.spec.kind}`);
|
|
250
|
-
|
|
251
|
-
const uniqueKeys = getUniquePartitionKeys(columnData.data);
|
|
252
|
-
if (!uniqueKeys) {
|
|
253
|
-
if (opts?.dontWaitAllData) continue;
|
|
254
|
-
return undefined;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (maxSplitIdx >= uniqueKeys.length)
|
|
258
|
-
throw new Error(`Not enough partition keys for the requested split axes in column ${spec.name}`);
|
|
259
|
-
|
|
260
|
-
// Pre-fetch labels for all involved split axes
|
|
261
|
-
const axesLabels: (Record<string | number, string> | undefined)[] = splitAxisIdxs
|
|
262
|
-
.map((idx) => this.findLabels(getAxisId(spec.axesSpec[idx])));
|
|
263
|
-
|
|
264
|
-
const keyCombinations: (string | number)[][] = [];
|
|
265
|
-
const generateCombinations = (currentCombo: (string | number)[], sAxisIdx: number) => {
|
|
266
|
-
if (sAxisIdx >= splitAxisIdxs.length) {
|
|
267
|
-
keyCombinations.push([...currentCombo]);
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
const axisIdx = splitAxisIdxs[sAxisIdx];
|
|
271
|
-
const axisValues = uniqueKeys[axisIdx];
|
|
272
|
-
for (const val of axisValues) {
|
|
273
|
-
currentCombo.push(val);
|
|
274
|
-
generateCombinations(currentCombo, sAxisIdx + 1);
|
|
275
|
-
currentCombo.pop();
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
generateCombinations([], 0);
|
|
279
|
-
|
|
280
|
-
// Generate entries for each key combination
|
|
281
|
-
for (const keyCombo of keyCombinations) {
|
|
282
|
-
const splitFilters: AxisFilterInfo[] = keyCombo.map((value, sAxisIdx) => {
|
|
283
|
-
const axisIdx = splitAxisIdxs[sAxisIdx];
|
|
284
|
-
const axisId = getAxisId(spec.axesSpec[axisIdx]);
|
|
285
|
-
const axisLabelMap = axesLabels[sAxisIdx];
|
|
286
|
-
const label = axisLabelMap?.[value] ?? String(value);
|
|
287
|
-
return { axisIdx, axisId, value: value as PValue, label };
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
result.push({
|
|
291
|
-
obj: spec,
|
|
292
|
-
ref,
|
|
293
|
-
axisFilters: splitFilters,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
124
|
+
for (const [key, value] of Object.entries(anchorsOrCtx)) {
|
|
125
|
+
if (isPlRef(value)) {
|
|
126
|
+
const resolvedSpec = this.getPColumnSpecByRef(value);
|
|
127
|
+
if (!resolvedSpec)
|
|
128
|
+
return undefined;
|
|
129
|
+
resolvedAnchors[key] = resolvedSpec;
|
|
297
130
|
} else {
|
|
298
|
-
|
|
299
|
-
for (const { ref, obj: spec } of filtered) {
|
|
300
|
-
if (!isPColumnSpec(spec)) continue;
|
|
301
|
-
result.push({
|
|
302
|
-
obj: spec,
|
|
303
|
-
ref,
|
|
304
|
-
// No splitFilters needed here
|
|
305
|
-
});
|
|
306
|
-
}
|
|
131
|
+
resolvedAnchors[key] = value;
|
|
307
132
|
}
|
|
308
133
|
}
|
|
309
|
-
|
|
310
|
-
if (result.length === 0)
|
|
311
|
-
return [];
|
|
312
|
-
|
|
313
|
-
const labelResults = deriveLabels(
|
|
314
|
-
result,
|
|
315
|
-
(o) => ({
|
|
316
|
-
spec: o.obj,
|
|
317
|
-
suffixTrace: splitFiltersToTrace(o.axisFilters), // Use helper function
|
|
318
|
-
}),
|
|
319
|
-
opts?.labelOps ?? {},
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
return labelResults.map((item) => ({
|
|
323
|
-
id: anchorIdDeriver.deriveS(
|
|
324
|
-
item.value.obj,
|
|
325
|
-
splitFiltersToAxisFilter(item.value.axisFilters), // Use helper function
|
|
326
|
-
),
|
|
327
|
-
obj: item.value.obj,
|
|
328
|
-
ref: item.value.ref,
|
|
329
|
-
axisFilters: item.value.axisFilters,
|
|
330
|
-
label: item.label,
|
|
331
|
-
}));
|
|
134
|
+
return new AnchoredIdDeriver(resolvedAnchors);
|
|
332
135
|
}
|
|
333
136
|
|
|
334
137
|
/**
|
|
@@ -343,83 +146,16 @@ export class ResultPool {
|
|
|
343
146
|
anchorsOrCtx: AnchoredIdDeriver | Record<string, PColumnSpec | PlRef>,
|
|
344
147
|
predicateOrSelectors: ((spec: PColumnSpec) => boolean) | APColumnSelectorWithSplit | APColumnSelectorWithSplit[],
|
|
345
148
|
opts?: UniversalPColumnOpts,
|
|
346
|
-
): PColumn<DataInfo<TreeNodeAccessor
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const entries = this.getUniversalPColumnEntries(
|
|
357
|
-
anchorsOrCtx,
|
|
358
|
-
predicateOrSelectors,
|
|
359
|
-
enhancedOpts,
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
if (!entries || entries.length === 0) return undefined;
|
|
363
|
-
|
|
364
|
-
const result: PColumn<DataInfo<TreeNodeAccessor>>[] = [];
|
|
365
|
-
|
|
366
|
-
for (const entry of entries) {
|
|
367
|
-
const columnData = this.getPColumnByRef(entry.ref);
|
|
368
|
-
if (!columnData) return undefined;
|
|
369
|
-
|
|
370
|
-
const parsedData = parsePColumnData(columnData.data);
|
|
371
|
-
if (!parsedData) return undefined;
|
|
372
|
-
|
|
373
|
-
let filteredEntries: JsonPartitionedDataInfoEntries<TreeNodeAccessor> | BinaryPartitionedDataInfoEntries<TreeNodeAccessor> = parsedData;
|
|
374
|
-
let spec = { ...columnData.spec };
|
|
375
|
-
|
|
376
|
-
if (entry.axisFilters && entry.axisFilters.length > 0) {
|
|
377
|
-
const axisFiltersByIdx = entry.axisFilters.map((filter) => [
|
|
378
|
-
filter.axisIdx,
|
|
379
|
-
filter.value,
|
|
380
|
-
] as [number, PValue]);
|
|
381
|
-
|
|
382
|
-
filteredEntries = filterDataInfoEntries(parsedData, axisFiltersByIdx);
|
|
383
|
-
|
|
384
|
-
const axisIndicesToRemove = [...entry.axisFilters]
|
|
385
|
-
.map((filter) => filter.axisIdx)
|
|
386
|
-
.sort((a, b) => b - a);
|
|
387
|
-
|
|
388
|
-
const newAxesSpec = [...spec.axesSpec];
|
|
389
|
-
for (const idx of axisIndicesToRemove) {
|
|
390
|
-
newAxesSpec.splice(idx, 1);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
spec = { ...spec, axesSpec: newAxesSpec };
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const dataInfo = entriesToDataInfo(filteredEntries);
|
|
397
|
-
|
|
398
|
-
if (spec.annotations) {
|
|
399
|
-
spec = {
|
|
400
|
-
...spec,
|
|
401
|
-
annotations: {
|
|
402
|
-
...spec.annotations,
|
|
403
|
-
'pl7.app/label': entry.label,
|
|
404
|
-
},
|
|
405
|
-
};
|
|
406
|
-
} else {
|
|
407
|
-
spec = {
|
|
408
|
-
...spec,
|
|
409
|
-
annotations: {
|
|
410
|
-
'pl7.app/label': entry.label,
|
|
411
|
-
},
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
result.push({
|
|
416
|
-
id: entry.id as unknown as PObjectId,
|
|
417
|
-
spec,
|
|
418
|
-
data: dataInfo,
|
|
149
|
+
): PColumn<DataInfo<TreeNodeAccessor> | TreeNodeAccessor>[] | undefined {
|
|
150
|
+
const anchorCtx = this.resolveAnchorCtx(anchorsOrCtx);
|
|
151
|
+
if (!anchorCtx) return undefined;
|
|
152
|
+
return new PColumnCollection()
|
|
153
|
+
.addColumnProvider(this)
|
|
154
|
+
.addAxisLabelProvider(this)
|
|
155
|
+
.getColumns(predicateOrSelectors, {
|
|
156
|
+
...opts,
|
|
157
|
+
anchorCtx,
|
|
419
158
|
});
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return result;
|
|
423
159
|
}
|
|
424
160
|
|
|
425
161
|
/**
|
|
@@ -456,9 +192,16 @@ export class ResultPool {
|
|
|
456
192
|
predicateOrSelectors: ((spec: PColumnSpec) => boolean) | APColumnSelectorWithSplit | APColumnSelectorWithSplit[],
|
|
457
193
|
opts?: UniversalPColumnOpts,
|
|
458
194
|
): { label: string; value: SUniversalPColumnId }[] | undefined {
|
|
459
|
-
const
|
|
195
|
+
const anchorCtx = this.resolveAnchorCtx(anchorsOrCtx);
|
|
196
|
+
if (!anchorCtx) return undefined;
|
|
197
|
+
const entries = new PColumnCollection()
|
|
198
|
+
.addColumnProvider(this)
|
|
199
|
+
.addAxisLabelProvider(this)
|
|
200
|
+
.getUniversalEntries(predicateOrSelectors, {
|
|
201
|
+
...opts,
|
|
202
|
+
anchorCtx,
|
|
203
|
+
});
|
|
460
204
|
if (!entries) return undefined;
|
|
461
|
-
// Generate final options using the entries from the helper method
|
|
462
205
|
return entries.map((item) => ({
|
|
463
206
|
value: item.id,
|
|
464
207
|
label: item.label,
|
|
@@ -658,6 +401,59 @@ export class ResultPool {
|
|
|
658
401
|
}
|
|
659
402
|
return undefined;
|
|
660
403
|
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Selects columns based on the provided selectors, returning PColumn objects
|
|
407
|
+
* with lazily loaded data.
|
|
408
|
+
*
|
|
409
|
+
* @param selectors - A predicate function, a single selector, or an array of selectors.
|
|
410
|
+
* @returns An array of PColumn objects matching the selectors. Data is loaded on first access.
|
|
411
|
+
*/
|
|
412
|
+
public selectColumns(
|
|
413
|
+
selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],
|
|
414
|
+
): PColumn<TreeNodeAccessor | undefined>[] {
|
|
415
|
+
const predicate = typeof selectors === 'function' ? selectors : selectorsToPredicate(selectors);
|
|
416
|
+
|
|
417
|
+
const matchedSpecs = this.getSpecs().entries.filter(({ obj: spec }) => {
|
|
418
|
+
if (!isPColumnSpec(spec)) return false;
|
|
419
|
+
return predicate(spec);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Map specs to PColumn objects with lazy data loading
|
|
423
|
+
return matchedSpecs.map(({ ref, obj: spec }) => {
|
|
424
|
+
// Type assertion needed because filter ensures it's PColumnSpec
|
|
425
|
+
const pcolumnSpec = spec as PColumnSpec;
|
|
426
|
+
let _cachedData: TreeNodeAccessor | undefined | null = null; // Use null to distinguish initial state from undefined result
|
|
427
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
428
|
+
const self = this; // Capture 'this' for use inside the getter
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
id: canonicalize(ref) as PObjectId,
|
|
432
|
+
spec: pcolumnSpec,
|
|
433
|
+
get data(): TreeNodeAccessor | undefined {
|
|
434
|
+
if (_cachedData !== null) {
|
|
435
|
+
return _cachedData; // Return cached data (could be undefined if fetch failed)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
_cachedData = self.getPColumnByRef(ref)?.data;
|
|
439
|
+
return _cachedData;
|
|
440
|
+
},
|
|
441
|
+
} satisfies PColumn<TreeNodeAccessor | undefined>; // Cast needed because 'data' is a getter
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Find labels data for a given axis id of a p-column.
|
|
447
|
+
* @returns a map of axis value => label
|
|
448
|
+
*/
|
|
449
|
+
public findLabelsForColumnAxis(column: PColumn<TreeNodeAccessor>, axisIdx: number): Record<string | number, string> | undefined {
|
|
450
|
+
const labels = this.findLabels(column.spec.axesSpec[axisIdx]);
|
|
451
|
+
if (!labels) return undefined;
|
|
452
|
+
return Object.fromEntries(column.data.listInputFields().map((field) => {
|
|
453
|
+
const r = JSON.parse(field) as [string];
|
|
454
|
+
return [r[axisIdx], labels[r[axisIdx]] ?? 'Unlabelled'];
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
661
457
|
}
|
|
662
458
|
|
|
663
459
|
/** Main entry point to the API available within model lambdas (like outputs, sections, etc..) */
|
|
@@ -727,6 +523,7 @@ export class RenderCtx<Args, UiState> {
|
|
|
727
523
|
// Removed redundant explicitColumns check
|
|
728
524
|
}
|
|
729
525
|
|
|
526
|
+
// TODO remove all non-PColumn fields
|
|
730
527
|
public createPFrame(def: PFrameDef<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>): PFrameHandle {
|
|
731
528
|
this.verifyInlineAndExplicitColumnsSupport(def);
|
|
732
529
|
return this.ctx.createPFrame(
|
|
@@ -734,6 +531,7 @@ export class RenderCtx<Args, UiState> {
|
|
|
734
531
|
);
|
|
735
532
|
}
|
|
736
533
|
|
|
534
|
+
// TODO remove all non-PColumn fields
|
|
737
535
|
public createPTable(def: PTableDef<PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>>): PTableHandle;
|
|
738
536
|
public createPTable(def: {
|
|
739
537
|
columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[];
|