@platforma-sdk/model 1.60.0 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/columns/column_collection_builder.cjs +15 -12
- package/dist/columns/column_collection_builder.cjs.map +1 -1
- package/dist/columns/column_collection_builder.d.ts +4 -2
- package/dist/columns/column_collection_builder.js +15 -12
- package/dist/columns/column_collection_builder.js.map +1 -1
- package/dist/columns/column_selector.cjs.map +1 -1
- package/dist/columns/column_selector.d.ts +3 -3
- package/dist/columns/column_selector.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/dist/render/api.cjs +14 -2
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +6 -2
- package/dist/render/api.js +14 -2
- package/dist/render/api.js.map +1 -1
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +10 -2
- package/dist/render/internal.js.map +1 -1
- package/package.json +7 -6
- package/src/columns/column_collection_builder.test.ts +24 -40
- package/src/columns/column_collection_builder.ts +17 -15
- package/src/columns/column_selector.ts +6 -5
- package/src/render/api.ts +23 -2
- package/src/render/internal.ts +18 -1
|
@@ -5,44 +5,26 @@ import type {
|
|
|
5
5
|
SUniversalPColumnId,
|
|
6
6
|
} from "@milaboratories/pl-model-common";
|
|
7
7
|
import { AnchoredIdDeriver } from "@milaboratories/pl-model-common";
|
|
8
|
+
import { SpecDriver } from "@milaboratories/pf-spec-driver";
|
|
8
9
|
|
|
9
|
-
import { describe, expect, test } from "vitest";
|
|
10
|
+
import { afterEach, describe, expect, test } from "vitest";
|
|
10
11
|
import type { ColumnSnapshotProvider } from "./column_snapshot_provider";
|
|
11
12
|
import type { ColumnSnapshot } from "./column_snapshot";
|
|
12
13
|
import { ColumnCollectionBuilder } from "./column_collection_builder";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
const drivers: SpecDriver[] = [];
|
|
15
16
|
|
|
16
17
|
function createSpecFrameCtx() {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
createSpecFrame: (specs: Record<string, PColumnSpec>) => {
|
|
22
|
-
const handle = `frame-${nextId++}`;
|
|
23
|
-
frames.set(handle, specs);
|
|
24
|
-
return handle;
|
|
25
|
-
},
|
|
26
|
-
specFrameDiscoverColumns: (handle: string, _request: any) => {
|
|
27
|
-
const specs = frames.get(handle)!;
|
|
28
|
-
return {
|
|
29
|
-
hits: Object.entries(specs).map(([columnId, spec]) => ({
|
|
30
|
-
hit: { columnId: columnId as PObjectId, spec },
|
|
31
|
-
mappingVariants: [
|
|
32
|
-
{
|
|
33
|
-
qualifications: { forQueries: [], forHit: [] },
|
|
34
|
-
distinctiveQualifications: { forQueries: [], forHit: [] },
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
})),
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
specFrameDispose: (handle: string) => {
|
|
41
|
-
frames.delete(handle);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
18
|
+
const driver = new SpecDriver();
|
|
19
|
+
drivers.push(driver);
|
|
20
|
+
return driver;
|
|
44
21
|
}
|
|
45
22
|
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
for (const driver of drivers) driver.dispose();
|
|
25
|
+
drivers.length = 0;
|
|
26
|
+
});
|
|
27
|
+
|
|
46
28
|
// --- Helpers ---
|
|
47
29
|
|
|
48
30
|
/** Default axis used when none specified — WASM requires at least one axis. */
|
|
@@ -173,15 +155,16 @@ describe("ColumnCollection.findColumns", () => {
|
|
|
173
155
|
expect(collection.findColumns()).toHaveLength(2);
|
|
174
156
|
});
|
|
175
157
|
|
|
176
|
-
test("exclude
|
|
158
|
+
test("exclude filters out matching columns", () => {
|
|
177
159
|
const s1 = createSnapshot("id1", createSpec("col1"));
|
|
160
|
+
const s2 = createSnapshot("id2", createSpec("col2"));
|
|
178
161
|
const builder = new ColumnCollectionBuilder(createSpecFrameCtx());
|
|
179
|
-
builder.addSource([s1]);
|
|
162
|
+
builder.addSource([s1, s2]);
|
|
180
163
|
|
|
181
164
|
const collection = builder.build()!;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
);
|
|
165
|
+
const results = collection.findColumns({ exclude: { name: "col1" } });
|
|
166
|
+
expect(results).toHaveLength(1);
|
|
167
|
+
expect(results[0].spec.name).toBe("col2");
|
|
185
168
|
});
|
|
186
169
|
});
|
|
187
170
|
|
|
@@ -377,15 +360,16 @@ describe("AnchoredColumnCollection", () => {
|
|
|
377
360
|
expect(matches[0].variants).toBeDefined();
|
|
378
361
|
});
|
|
379
362
|
|
|
380
|
-
test("findColumns exclude
|
|
381
|
-
const
|
|
363
|
+
test("findColumns exclude filters out matching columns", () => {
|
|
364
|
+
const snap1 = createSnapshot("id1", createSpec("col1", { axesSpec: [sampleAxis("sample")] }));
|
|
365
|
+
const snap2 = createSnapshot("id2", createSpec("col2", { axesSpec: [sampleAxis("sample")] }));
|
|
382
366
|
const builder = new ColumnCollectionBuilder(createSpecFrameCtx());
|
|
383
|
-
builder.addSource([
|
|
367
|
+
builder.addSource([snap1, snap2]);
|
|
384
368
|
|
|
385
369
|
const collection = builder.build({ anchors: { main: anchorSpec } })!;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
);
|
|
370
|
+
const results = collection.findColumns({ exclude: { name: "col1" } });
|
|
371
|
+
expect(results).toHaveLength(1);
|
|
372
|
+
expect(results[0].column.spec.name).toBe("col2");
|
|
389
373
|
});
|
|
390
374
|
|
|
391
375
|
test("allowPartialColumnList with anchors tracks completeness", () => {
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AxisQualification,
|
|
3
3
|
ColumnAxesWithQualifications,
|
|
4
4
|
DiscoverColumnsConstraints,
|
|
5
|
+
DiscoverColumnsStepInfo,
|
|
5
6
|
MultiColumnSelector,
|
|
6
7
|
NativePObjectId,
|
|
7
8
|
PColumnSpec,
|
|
@@ -23,7 +24,7 @@ import type { GlobalCfgRenderCtxMethods } from "../render/internal";
|
|
|
23
24
|
/** Subset of render context methods needed for spec frame operations. */
|
|
24
25
|
type SpecFrameCtx = Pick<
|
|
25
26
|
GlobalCfgRenderCtxMethods,
|
|
26
|
-
"createSpecFrame" | "specFrameDiscoverColumns" | "
|
|
27
|
+
"createSpecFrame" | "specFrameDiscoverColumns" | "disposeSpecFrame"
|
|
27
28
|
>;
|
|
28
29
|
|
|
29
30
|
// --- FindColumnsOptions ---
|
|
@@ -79,6 +80,8 @@ export interface ColumnMatch {
|
|
|
79
80
|
readonly originalId: PObjectId;
|
|
80
81
|
/** Match variants — different paths/qualifications that reach this column. */
|
|
81
82
|
readonly variants: MatchVariant[];
|
|
83
|
+
/** Linker steps traversed to reach this hit; empty for direct matches. */
|
|
84
|
+
readonly path: DiscoverColumnsStepInfo[];
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/** Qualifications needed for both query (already-integrated) columns and the hit column. */
|
|
@@ -253,24 +256,23 @@ class ColumnCollectionImpl implements ColumnCollection {
|
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {
|
|
256
|
-
const
|
|
259
|
+
const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;
|
|
260
|
+
const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;
|
|
257
261
|
|
|
258
262
|
const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
|
|
259
|
-
|
|
263
|
+
includeColumns,
|
|
264
|
+
excludeColumns,
|
|
260
265
|
axes: [],
|
|
266
|
+
maxHops: 0,
|
|
261
267
|
constraints: PLAIN_CONSTRAINTS,
|
|
262
268
|
});
|
|
263
269
|
|
|
264
270
|
// Map hits back to snapshots
|
|
265
|
-
|
|
271
|
+
const results = response.hits
|
|
266
272
|
.map((hit) => this.columns.get(hit.hit.columnId as PObjectId))
|
|
267
273
|
.filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined)
|
|
268
274
|
.map((col) => this.toSnapshot(col));
|
|
269
275
|
|
|
270
|
-
if (options?.exclude) {
|
|
271
|
-
throw new Error("Exclude filter is not yet implemented for plain ColumnCollection");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
276
|
return results;
|
|
275
277
|
}
|
|
276
278
|
|
|
@@ -336,16 +338,19 @@ class AnchoredColumnCollectionImpl implements AnchoredColumnCollection {
|
|
|
336
338
|
findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {
|
|
337
339
|
const mode = options?.mode ?? "enrichment";
|
|
338
340
|
const constraints = matchingModeToConstraints(mode);
|
|
339
|
-
const
|
|
341
|
+
const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;
|
|
342
|
+
const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;
|
|
340
343
|
|
|
341
344
|
const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
|
|
342
|
-
|
|
345
|
+
includeColumns,
|
|
346
|
+
excludeColumns,
|
|
343
347
|
constraints,
|
|
344
348
|
axes: this.anchorAxes,
|
|
349
|
+
maxHops: options?.maxHops ?? 4,
|
|
345
350
|
});
|
|
346
351
|
|
|
347
352
|
// Map hits back to ColumnMatch entries
|
|
348
|
-
|
|
353
|
+
const results = response.hits
|
|
349
354
|
.map((hit) => {
|
|
350
355
|
const origId = hit.hit.columnId as PObjectId;
|
|
351
356
|
const col = this.columns.get(origId);
|
|
@@ -360,14 +365,11 @@ class AnchoredColumnCollectionImpl implements AnchoredColumnCollection {
|
|
|
360
365
|
distinctiveQualifications: v.distinctiveQualifications,
|
|
361
366
|
}),
|
|
362
367
|
),
|
|
368
|
+
path: hit.path,
|
|
363
369
|
} satisfies ColumnMatch;
|
|
364
370
|
})
|
|
365
371
|
.filter((m): m is ColumnMatch => m !== undefined);
|
|
366
372
|
|
|
367
|
-
if (options?.exclude) {
|
|
368
|
-
throw new Error("Exclude filter is not yet implemented for AnchoredColumnCollection");
|
|
369
|
-
}
|
|
370
|
-
|
|
371
373
|
return results;
|
|
372
374
|
}
|
|
373
375
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AxisValueType,
|
|
3
|
+
ColumnValueType,
|
|
2
4
|
MultiAxisSelector,
|
|
3
5
|
MultiColumnSelector,
|
|
4
6
|
PColumnSpec,
|
|
5
7
|
StringMatcher,
|
|
6
|
-
ValueType,
|
|
7
8
|
} from "@milaboratories/pl-model-common";
|
|
8
9
|
|
|
9
10
|
export type { StringMatcher } from "@milaboratories/pl-model-common";
|
|
@@ -19,7 +20,7 @@ export type RelaxedRecord = Record<string, RelaxedStringMatchers>;
|
|
|
19
20
|
/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */
|
|
20
21
|
export interface RelaxedAxisSelector {
|
|
21
22
|
name?: RelaxedStringMatchers;
|
|
22
|
-
type?:
|
|
23
|
+
type?: AxisValueType | AxisValueType[];
|
|
23
24
|
domain?: RelaxedRecord;
|
|
24
25
|
contextDomain?: RelaxedRecord;
|
|
25
26
|
annotations?: RelaxedRecord;
|
|
@@ -28,7 +29,7 @@ export interface RelaxedAxisSelector {
|
|
|
28
29
|
/** Relaxed column selector — convenient hand-written form. */
|
|
29
30
|
export interface RelaxedColumnSelector {
|
|
30
31
|
name?: RelaxedStringMatchers;
|
|
31
|
-
type?:
|
|
32
|
+
type?: ColumnValueType | ColumnValueType[];
|
|
32
33
|
domain?: RelaxedRecord;
|
|
33
34
|
contextDomain?: RelaxedRecord;
|
|
34
35
|
annotations?: RelaxedRecord;
|
|
@@ -57,7 +58,7 @@ function normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]>
|
|
|
57
58
|
return result;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
function normalizeTypes(input:
|
|
61
|
+
function normalizeTypes<T>(input: T | T[]): T[] {
|
|
61
62
|
return Array.isArray(input) ? input : [input];
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -140,7 +141,7 @@ function matchAxisSelector(
|
|
|
140
141
|
selector: MultiAxisSelector,
|
|
141
142
|
): boolean {
|
|
142
143
|
if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;
|
|
143
|
-
if (selector.type !== undefined && !selector.type.includes(axis.type
|
|
144
|
+
if (selector.type !== undefined && !selector.type.includes(axis.type)) return false;
|
|
144
145
|
if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))
|
|
145
146
|
return false;
|
|
146
147
|
if (
|
package/src/render/api.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AnchoredPColumnSelector,
|
|
3
3
|
AnyFunction,
|
|
4
|
+
AxesId,
|
|
5
|
+
AxesSpec,
|
|
4
6
|
AxisId,
|
|
5
7
|
DataInfo,
|
|
6
8
|
DiscoverColumnsRequest,
|
|
@@ -17,6 +19,8 @@ import type {
|
|
|
17
19
|
PObjectId,
|
|
18
20
|
PObjectSpec,
|
|
19
21
|
PSpecPredicate,
|
|
22
|
+
PTableColumnId,
|
|
23
|
+
PTableColumnSpec,
|
|
20
24
|
PTableDef,
|
|
21
25
|
PTableDefV2,
|
|
22
26
|
PTableHandle,
|
|
@@ -25,6 +29,7 @@ import type {
|
|
|
25
29
|
PlRef,
|
|
26
30
|
ResolveAnchorsOptions,
|
|
27
31
|
ResultCollection,
|
|
32
|
+
SingleAxisSelector,
|
|
28
33
|
SUniversalPColumnId,
|
|
29
34
|
ValueOrError,
|
|
30
35
|
} from "@milaboratories/pl-model-common";
|
|
@@ -727,8 +732,24 @@ export abstract class RenderCtxBase<Args = unknown, Data = unknown> {
|
|
|
727
732
|
return this.ctx.specFrameDiscoverColumns(handle, request);
|
|
728
733
|
}
|
|
729
734
|
|
|
730
|
-
public
|
|
731
|
-
this.ctx.
|
|
735
|
+
public disposeSpecFrame(handle: string): void {
|
|
736
|
+
this.ctx.disposeSpecFrame(handle);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
public expandAxes(spec: AxesSpec): AxesId {
|
|
740
|
+
return this.ctx.expandAxes(spec);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
public collapseAxes(ids: AxesId): AxesSpec {
|
|
744
|
+
return this.ctx.collapseAxes(ids);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
public findAxis(spec: AxesSpec, selector: SingleAxisSelector): number {
|
|
748
|
+
return this.ctx.findAxis(spec, selector);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
public findTableColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number {
|
|
752
|
+
return this.ctx.findTableColumn(tableSpec, selector);
|
|
732
753
|
}
|
|
733
754
|
|
|
734
755
|
public getCurrentUnstableMarker(): string | undefined {
|
package/src/render/internal.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { Optional } from "utility-types";
|
|
2
2
|
import type {
|
|
3
|
+
AxesId,
|
|
4
|
+
AxesSpec,
|
|
3
5
|
Branded,
|
|
4
6
|
DiscoverColumnsRequest,
|
|
5
7
|
DiscoverColumnsResponse,
|
|
8
|
+
PTableColumnId,
|
|
9
|
+
PTableColumnSpec,
|
|
10
|
+
SingleAxisSelector,
|
|
6
11
|
StringifiedJson,
|
|
7
12
|
} from "@milaboratories/pl-model-common";
|
|
8
13
|
import type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from "./traversal_ops";
|
|
@@ -174,7 +179,19 @@ export interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = F
|
|
|
174
179
|
request: DiscoverColumnsRequest,
|
|
175
180
|
): DiscoverColumnsResponse;
|
|
176
181
|
|
|
177
|
-
|
|
182
|
+
disposeSpecFrame(handle: string): void;
|
|
183
|
+
|
|
184
|
+
/** Expand index-based parentAxes in AxesSpec to resolved AxisId parents in AxesId. */
|
|
185
|
+
expandAxes(spec: AxesSpec): AxesId;
|
|
186
|
+
|
|
187
|
+
/** Collapse resolved AxisId parents back to index-based parentAxes in AxesSpec. */
|
|
188
|
+
collapseAxes(ids: AxesId): AxesSpec;
|
|
189
|
+
|
|
190
|
+
/** Find the index of an axis matching the given selector. Returns -1 if not found. */
|
|
191
|
+
findAxis(spec: AxesSpec, selector: SingleAxisSelector): number;
|
|
192
|
+
|
|
193
|
+
/** Find the flat index of a table column matching the given selector. Returns -1 if not found. */
|
|
194
|
+
findTableColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number;
|
|
178
195
|
|
|
179
196
|
//
|
|
180
197
|
// Computable
|