@milaboratories/pl-model-common 1.46.3 → 1.47.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/accessor_traversal.cjs +119 -0
- package/dist/columns/accessor_traversal.cjs.map +1 -0
- package/dist/columns/accessor_traversal.d.ts +52 -0
- package/dist/columns/accessor_traversal.d.ts.map +1 -0
- package/dist/columns/accessor_traversal.js +114 -0
- package/dist/columns/accessor_traversal.js.map +1 -0
- package/dist/columns/column_registry.cjs +40 -0
- package/dist/columns/column_registry.cjs.map +1 -0
- package/dist/columns/column_registry.d.ts +31 -0
- package/dist/columns/column_registry.d.ts.map +1 -0
- package/dist/columns/column_registry.js +40 -0
- package/dist/columns/column_registry.js.map +1 -0
- package/dist/columns/column_selector.cjs +49 -0
- package/dist/columns/column_selector.cjs.map +1 -0
- package/dist/columns/column_selector.d.ts +33 -0
- package/dist/columns/column_selector.d.ts.map +1 -0
- package/dist/columns/column_selector.js +47 -0
- package/dist/columns/column_selector.js.map +1 -0
- package/dist/columns/dedup.cjs +47 -0
- package/dist/columns/dedup.cjs.map +1 -0
- package/dist/columns/dedup.d.ts +27 -0
- package/dist/columns/dedup.d.ts.map +1 -0
- package/dist/columns/dedup.js +47 -0
- package/dist/columns/dedup.js.map +1 -0
- package/dist/columns/index.cjs +18 -0
- package/dist/columns/index.d.ts +8 -0
- package/dist/columns/index.js +6 -0
- package/dist/columns/providers.cjs +62 -0
- package/dist/columns/providers.cjs.map +1 -0
- package/dist/columns/providers.d.ts +39 -0
- package/dist/columns/providers.d.ts.map +1 -0
- package/dist/columns/providers.js +61 -0
- package/dist/columns/providers.js.map +1 -0
- package/dist/columns/types.d.ts +108 -0
- package/dist/columns/types.d.ts.map +1 -0
- package/dist/driver_kit.d.ts +1 -2
- package/dist/driver_kit.d.ts.map +1 -1
- package/dist/drivers/columns/columns_collection_driver.d.ts +124 -0
- package/dist/drivers/columns/columns_collection_driver.d.ts.map +1 -0
- package/dist/drivers/columns/discover_columns_options.cjs +28 -0
- package/dist/drivers/columns/discover_columns_options.cjs.map +1 -0
- package/dist/drivers/columns/discover_columns_options.d.ts +64 -0
- package/dist/drivers/columns/discover_columns_options.d.ts.map +1 -0
- package/dist/drivers/columns/discover_columns_options.js +28 -0
- package/dist/drivers/columns/discover_columns_options.js.map +1 -0
- package/dist/drivers/columns/index.d.ts +3 -0
- package/dist/drivers/index.cjs +32 -7
- package/dist/drivers/index.d.ts +12 -9
- package/dist/drivers/index.js +6 -4
- package/dist/drivers/pframe/driver.d.ts +1 -2
- package/dist/drivers/pframe/driver.d.ts.map +1 -1
- package/dist/drivers/pframe/index.cjs +30 -7
- package/dist/drivers/pframe/index.d.ts +9 -8
- package/dist/drivers/pframe/index.js +5 -4
- package/dist/drivers/pframe/query/index.d.ts +2 -2
- package/dist/drivers/pframe/query/query_common.d.ts +24 -1
- package/dist/drivers/pframe/query/query_common.d.ts.map +1 -1
- package/dist/drivers/pframe/query/query_spec.d.ts +25 -24
- package/dist/drivers/pframe/query/query_spec.d.ts.map +1 -1
- package/dist/drivers/pframe/query/utils.cjs +18 -8
- package/dist/drivers/pframe/query/utils.cjs.map +1 -1
- package/dist/drivers/pframe/query/utils.d.ts +5 -1
- package/dist/drivers/pframe/query/utils.d.ts.map +1 -1
- package/dist/drivers/pframe/query/utils.js +18 -8
- package/dist/drivers/pframe/query/utils.js.map +1 -1
- package/dist/drivers/pframe/spec/anchored.d.ts +2 -2
- package/dist/drivers/pframe/spec/discovered_column.cjs +31 -15
- package/dist/drivers/pframe/spec/discovered_column.cjs.map +1 -1
- package/dist/drivers/pframe/spec/discovered_column.d.ts +23 -13
- package/dist/drivers/pframe/spec/discovered_column.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/discovered_column.js +26 -12
- package/dist/drivers/pframe/spec/discovered_column.js.map +1 -1
- package/dist/drivers/pframe/spec/filtered_column.cjs +46 -0
- package/dist/drivers/pframe/spec/filtered_column.cjs.map +1 -1
- package/dist/drivers/pframe/spec/filtered_column.d.ts +39 -1
- package/dist/drivers/pframe/spec/filtered_column.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/filtered_column.js +41 -1
- package/dist/drivers/pframe/spec/filtered_column.js.map +1 -1
- package/dist/drivers/pframe/spec/ids.cjs +62 -10
- package/dist/drivers/pframe/spec/ids.cjs.map +1 -1
- package/dist/drivers/pframe/spec/ids.d.ts +48 -15
- package/dist/drivers/pframe/spec/ids.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/ids.js +60 -9
- package/dist/drivers/pframe/spec/ids.js.map +1 -1
- package/dist/drivers/pframe/spec/index.cjs +30 -7
- package/dist/drivers/pframe/spec/index.d.ts +6 -5
- package/dist/drivers/pframe/spec/index.js +5 -4
- package/dist/drivers/pframe/spec/native_id.cjs +1 -0
- package/dist/drivers/pframe/spec/native_id.cjs.map +1 -1
- package/dist/drivers/pframe/spec/native_id.js +1 -0
- package/dist/drivers/pframe/spec/native_id.js.map +1 -1
- package/dist/drivers/pframe/spec/overridden.cjs +212 -0
- package/dist/drivers/pframe/spec/overridden.cjs.map +1 -0
- package/dist/drivers/pframe/spec/overridden.d.ts +67 -0
- package/dist/drivers/pframe/spec/overridden.d.ts.map +1 -0
- package/dist/drivers/pframe/spec/overridden.js +202 -0
- package/dist/drivers/pframe/spec/overridden.js.map +1 -0
- package/dist/drivers/pframe/spec/selectors.cjs +1 -0
- package/dist/drivers/pframe/spec/selectors.cjs.map +1 -1
- package/dist/drivers/pframe/spec/selectors.d.ts +3 -0
- package/dist/drivers/pframe/spec/selectors.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/selectors.js +1 -0
- package/dist/drivers/pframe/spec/selectors.js.map +1 -1
- package/dist/drivers/pframe/spec/spec.cjs.map +1 -1
- package/dist/drivers/pframe/spec/spec.d.ts +2 -3
- package/dist/drivers/pframe/spec/spec.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/spec.js.map +1 -1
- package/dist/drivers/pframe/spec_driver.d.ts +2 -2
- package/dist/drivers/pframe/spec_driver.d.ts.map +1 -1
- package/dist/drivers/pframe/table_calculate.cjs +2 -2
- package/dist/drivers/pframe/table_calculate.cjs.map +1 -1
- package/dist/drivers/pframe/table_calculate.d.ts +6 -2
- package/dist/drivers/pframe/table_calculate.d.ts.map +1 -1
- package/dist/drivers/pframe/table_calculate.js +2 -2
- package/dist/drivers/pframe/table_calculate.js.map +1 -1
- package/dist/drivers/pframe/table_common.cjs.map +1 -1
- package/dist/drivers/pframe/table_common.d.ts +11 -4
- package/dist/drivers/pframe/table_common.d.ts.map +1 -1
- package/dist/drivers/pframe/table_common.js.map +1 -1
- package/dist/index.cjs +63 -10
- package/dist/index.d.ts +20 -11
- package/dist/index.js +15 -6
- package/dist/pool/index.cjs +18 -0
- package/dist/pool/index.d.ts +2 -2
- package/dist/pool/index.js +3 -0
- package/dist/pool/spec.cjs +59 -11
- package/dist/pool/spec.cjs.map +1 -1
- package/dist/pool/spec.d.ts +24 -9
- package/dist/pool/spec.d.ts.map +1 -1
- package/dist/pool/spec.js +50 -10
- package/dist/pool/spec.js.map +1 -1
- package/dist/services/index.d.ts +2 -2
- package/dist/services/service_declarations.cjs +22 -0
- package/dist/services/service_declarations.cjs.map +1 -1
- package/dist/services/service_declarations.d.ts +5 -3
- package/dist/services/service_declarations.d.ts.map +1 -1
- package/dist/services/service_declarations.js +22 -0
- package/dist/services/service_declarations.js.map +1 -1
- package/dist/services/service_registry.cjs.map +1 -1
- package/dist/services/service_registry.d.ts +3 -3
- package/dist/services/service_registry.d.ts.map +1 -1
- package/dist/services/service_registry.js.map +1 -1
- package/dist/services/service_types.cjs.map +1 -1
- package/dist/services/service_types.d.ts +25 -9
- package/dist/services/service_types.d.ts.map +1 -1
- package/dist/services/service_types.js.map +1 -1
- package/package.json +3 -2
- package/src/columns/accessor_traversal.ts +139 -0
- package/src/columns/column_registry.ts +41 -0
- package/src/columns/column_selector.ts +100 -0
- package/src/columns/dedup.ts +49 -0
- package/src/columns/index.ts +6 -0
- package/src/columns/providers.ts +74 -0
- package/src/columns/types.ts +116 -0
- package/src/drivers/columns/columns_collection_driver.ts +146 -0
- package/src/drivers/columns/discover_columns_options.ts +91 -0
- package/src/drivers/columns/index.ts +2 -0
- package/src/drivers/index.ts +1 -0
- package/src/drivers/pframe/index.ts +0 -1
- package/src/drivers/pframe/query/query_common.ts +24 -0
- package/src/drivers/pframe/query/query_spec.ts +38 -25
- package/src/drivers/pframe/query/utils.test.ts +6 -6
- package/src/drivers/pframe/query/utils.ts +27 -7
- package/src/drivers/pframe/spec/discovered_column.ts +43 -28
- package/src/drivers/pframe/spec/filtered_column.ts +66 -0
- package/src/drivers/pframe/spec/ids.ts +142 -17
- package/src/drivers/pframe/spec/index.ts +1 -0
- package/src/drivers/pframe/spec/overridden.ts +285 -0
- package/src/drivers/pframe/spec/selectors.ts +3 -0
- package/src/drivers/pframe/spec/spec.ts +7 -3
- package/src/drivers/pframe/spec_driver.ts +3 -3
- package/src/drivers/pframe/table_calculate.ts +13 -3
- package/src/drivers/pframe/table_common.ts +10 -3
- package/src/index.ts +1 -0
- package/src/pool/spec.ts +69 -23
- package/src/services/service_declarations.ts +31 -0
- package/src/services/service_registry.ts +8 -4
- package/src/services/service_types.ts +35 -9
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Branded } from "../branding";
|
|
2
|
+
import type { PObjectId } from "../pool";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Opaque sandbox/host accessor handle.
|
|
6
|
+
*
|
|
7
|
+
* Both the sandbox `TreeNodeAccessor.handle` and the host-issued accessor
|
|
8
|
+
* keys alias this brand — `sdk/model` re-exports the same type so the two
|
|
9
|
+
* sides stay structurally identical.
|
|
10
|
+
*/
|
|
11
|
+
export type AccessorHandle = Branded<string, "AccessorHandle">;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Structural subset of {@link FieldTraversalStep} (from `@platforma-sdk/model`)
|
|
15
|
+
* needed by the host/sandbox column-providers traversal.
|
|
16
|
+
*
|
|
17
|
+
* Defined locally so this module does not depend on the sandbox `render`
|
|
18
|
+
* subtree. Both `TreeNodeAccessor.traverse` (sandbox) and
|
|
19
|
+
* `PlTreeNodeAccessor.traverse` (host) accept a superset of these fields, so
|
|
20
|
+
* structural compatibility is preserved.
|
|
21
|
+
*/
|
|
22
|
+
export interface FieldTraversalStepLike {
|
|
23
|
+
/** Field name */
|
|
24
|
+
readonly field: string;
|
|
25
|
+
/** Asserted field type — used by `accessor.traverse` to validate. */
|
|
26
|
+
readonly assertFieldType?: "Input" | "Output" | "Service" | "OTW" | "Dynamic" | "MTW";
|
|
27
|
+
/** Don't terminate chain if current resource or field has an error associated. */
|
|
28
|
+
readonly ignoreError?: true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Raw entry returned by {@link GlobalCfgRenderCtxMethods.getUpstreamBlockCtx}
|
|
33
|
+
* on the sandbox side, or by `collectUpstreamBlockCtx` on the host side.
|
|
34
|
+
* Carries handle ids only — providers wrap them into accessor instances as
|
|
35
|
+
* needed.
|
|
36
|
+
*
|
|
37
|
+
* Generic over the handle type so the same shape backs both:
|
|
38
|
+
* - sandbox (`AHandle = AccessorHandle`, a `Branded<string, "AccessorHandle">`)
|
|
39
|
+
* - host (`AHandle = PlTreeNodeAccessor`, the resolved accessor instance)
|
|
40
|
+
*
|
|
41
|
+
* Default `AHandle = string` since `AccessorHandle` is a brand on `string` —
|
|
42
|
+
* the default is safe for the sandbox case.
|
|
43
|
+
*/
|
|
44
|
+
export interface UpstreamBlockCtx<AHandle = string> {
|
|
45
|
+
blockId: string;
|
|
46
|
+
prodCtx?: AHandle;
|
|
47
|
+
stagingCtx?: AHandle;
|
|
48
|
+
/** True when the `prodCtx` ctx-holder exists but `prodUiCtx` is still rendering. */
|
|
49
|
+
prodIncomplete?: boolean;
|
|
50
|
+
/** True when the `stagingCtx` ctx-holder exists but `stagingUiCtx` is still rendering. */
|
|
51
|
+
stagingIncomplete?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Minimal accessor surface used by column-providers / column-registry
|
|
56
|
+
* traversal.
|
|
57
|
+
*
|
|
58
|
+
* Both sandbox `TreeNodeAccessor` and host `PlTreeNodeAccessor` satisfy this
|
|
59
|
+
* contract directly — `traverse(step)` is defined on both, and the other
|
|
60
|
+
* members already match by shape. No `resolvePath` member: when canonical
|
|
61
|
+
* `PObjectId`s are required (local-id construction inside the
|
|
62
|
+
* outputs/prerun branch), the traversal helpers thread the path explicitly.
|
|
63
|
+
*/
|
|
64
|
+
export interface AccessorLike<Self extends AccessorLike<Self>> {
|
|
65
|
+
/** Resource type carried by the underlying node (only `.name` is used). */
|
|
66
|
+
readonly resourceType: { readonly name: string };
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Single-step field traversal. Returns `undefined` when the field is
|
|
70
|
+
* absent / unresolved (with `ignoreError`). Same shape on sandbox and host —
|
|
71
|
+
* sandbox `TreeNodeAccessor.traverse` is an alias for `resolveAny` and host
|
|
72
|
+
* `PlTreeNodeAccessor.traverse` is the canonical method.
|
|
73
|
+
*/
|
|
74
|
+
traverse(step: FieldTraversalStepLike): Self | undefined;
|
|
75
|
+
|
|
76
|
+
/** List input-field names on this node. */
|
|
77
|
+
listInputFields(): string[];
|
|
78
|
+
|
|
79
|
+
/** Whether the input-field collection on this node is finalized. */
|
|
80
|
+
getInputsLocked(): boolean;
|
|
81
|
+
|
|
82
|
+
/** Whether this node has a data payload attached. */
|
|
83
|
+
hasData(): boolean;
|
|
84
|
+
|
|
85
|
+
/** Decode the data payload as JSON. Returns `undefined` if no data. */
|
|
86
|
+
getDataAsJson<T = unknown>(): T | undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* One indexed column — the canonical record produced by every traversal.
|
|
91
|
+
* Carries everything needed to read spec/data/status under a stable id.
|
|
92
|
+
*
|
|
93
|
+
* Generic over the accessor flavour so the same record shape works for both
|
|
94
|
+
* the sandbox `TreeNodeAccessor` and the host `PlTreeNodeAccessor`.
|
|
95
|
+
*/
|
|
96
|
+
export type LeafEntry<A extends AccessorLike<A>> = {
|
|
97
|
+
/** PFrame accessor that owns `<name>.spec` / `<name>.data` fields. */
|
|
98
|
+
accessor: A;
|
|
99
|
+
/** Field-name prefix inside the PFrame. */
|
|
100
|
+
name: string;
|
|
101
|
+
/** Canonical id under which this column is reachable. */
|
|
102
|
+
id: PObjectId;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Base interface for id-indexed column providers — the surface
|
|
107
|
+
* {@link ColumnRegistry} consumes. Generic over the concrete accessor flavour
|
|
108
|
+
* so it can back both sandbox (`TreeNodeAccessor`) and host
|
|
109
|
+
* (`PlTreeNodeAccessor` adapter) registries.
|
|
110
|
+
*/
|
|
111
|
+
export interface ColumnEntriesProvider<A extends AccessorLike<A>> {
|
|
112
|
+
/** Map of canonical {@link PObjectId} → {@link LeafEntry} for every column reachable from this source. */
|
|
113
|
+
getPObjectEntries(): ReadonlyMap<PObjectId, LeafEntry<A>>;
|
|
114
|
+
/** Whether enumeration of columns from this source has finalised. */
|
|
115
|
+
isFinal(): boolean;
|
|
116
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { Branded } from "../../branding";
|
|
2
|
+
import type { PoolEntry } from "../../pool_entry";
|
|
3
|
+
import type { AccessorHandle, AccessorLike, UpstreamBlockCtx } from "../../columns/types";
|
|
4
|
+
import type { ColumnUniversalId } from "../pframe/spec/ids";
|
|
5
|
+
import type { ColumnsDiscoverOptions, ColumnsFilterOptions } from "./discover_columns_options";
|
|
6
|
+
import type { PFrameSpecDriver } from "../pframe/spec_driver";
|
|
7
|
+
import type { PColumnSpec } from "../pframe/spec/spec";
|
|
8
|
+
import type { PObjectId } from "../../pool";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Opaque host-owned handle for a `ColumnsCollection` instance. Issued by
|
|
12
|
+
* {@link ColumnsCollectionDriver.create}, refcounted by the driver, and
|
|
13
|
+
* pinned to the active render ctx via the VM injector — sandbox never
|
|
14
|
+
* sees raw refcounting.
|
|
15
|
+
*/
|
|
16
|
+
export type CollectionHandle = Branded<string, "CollectionHandle">;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* JSON descriptor crossing the VM bridge in place of a sandbox
|
|
20
|
+
* `ColumnsSource`. Always plain data — no closures, no class instances.
|
|
21
|
+
*
|
|
22
|
+
* - `"collection"` – reference another driver-managed collection by handle
|
|
23
|
+
* (chaining, splicing).
|
|
24
|
+
* - `"result_pool"` – fan-out into the host's current render ctx upstream
|
|
25
|
+
* block ctxes. Carries no payload — the host always uses its own pool.
|
|
26
|
+
* - `"accessor"` – walk the host tree starting at the given accessor
|
|
27
|
+
* handle from a `path` prefix.
|
|
28
|
+
* - `"ids"` – pre-resolved id list (sandbox-materialised provider).
|
|
29
|
+
*/
|
|
30
|
+
export type SerializedColumnsSource =
|
|
31
|
+
| { readonly kind: "collection"; readonly handle: CollectionHandle }
|
|
32
|
+
| { readonly kind: "result_pool" }
|
|
33
|
+
| { readonly kind: "accessor"; readonly accessor: AccessorHandle; readonly path: string[] }
|
|
34
|
+
| { readonly kind: "ids"; readonly ids: ColumnUniversalId[]; readonly isFinal: boolean };
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Per-call host bindings the driver needs to resolve sources whose
|
|
38
|
+
* shape references render-ctx state (`"accessor"`, `"result_pool"`).
|
|
39
|
+
*
|
|
40
|
+
* The VM injector inside `pl-middle-layer` supplies these on every call;
|
|
41
|
+
* UI-side direct callers that only build collections out of `"ids"` /
|
|
42
|
+
* `"collection"` sources may omit the bindings entirely.
|
|
43
|
+
*
|
|
44
|
+
* Parameterised on the concrete accessor flavour so host implementations
|
|
45
|
+
* keep their static types (e.g. `PlTreeNodeAccessor`) without leaking that
|
|
46
|
+
* dependency into `@milaboratories/pl-model-common`.
|
|
47
|
+
*/
|
|
48
|
+
export interface ColumnsCollectionDriverHost<A extends AccessorLike<A> = AccessorLike<any>> {
|
|
49
|
+
/** Resolve an {@link AccessorHandle} to the host's concrete accessor. */
|
|
50
|
+
resolveAccessor(handle: AccessorHandle): A;
|
|
51
|
+
|
|
52
|
+
/** Snapshot of upstream-block ctx pairs from the current render ctx. */
|
|
53
|
+
getUpstreamBlockCtxes(): ReadonlyArray<UpstreamBlockCtx<A>>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Per-call spec driver. The injector supplies the active render ctx's
|
|
57
|
+
* `PFrameSpec` service; `discover` / `filter` use it to build a spec
|
|
58
|
+
* frame and run a single discovery query.
|
|
59
|
+
*/
|
|
60
|
+
getSpecDriver(): PFrameSpecDriver;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the canonical {@link PColumnSpec} for a leaf {@link PObjectId}.
|
|
64
|
+
* Returns `undefined` when the id is not present in the active registry
|
|
65
|
+
* (e.g. handed to the driver via a `{kind:"ids"}` source whose underlying
|
|
66
|
+
* column has since left the visible scope). Override-wrapped ids are
|
|
67
|
+
* unwrapped by the caller — this method only resolves the underlying leaf.
|
|
68
|
+
*/
|
|
69
|
+
resolveSpec(id: PObjectId): PColumnSpec | undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sandbox / UI view of the `ColumnsCollection` driver. Same methods as
|
|
74
|
+
* {@link ColumnsCollectionDriver}, but the `host` parameters are dropped —
|
|
75
|
+
* the VM bridge / UI wrapper supplies them on every call so callers only
|
|
76
|
+
* pass plain data (handles + source descriptors + option objects).
|
|
77
|
+
*
|
|
78
|
+
* `getService("columnsCollection")` returns a value of this shape on both
|
|
79
|
+
* sandbox and UI sides.
|
|
80
|
+
*/
|
|
81
|
+
export interface ColumnsCollectionDriverModel {
|
|
82
|
+
/** Build a fresh collection from the supplied source descriptors. */
|
|
83
|
+
create(sources: ReadonlyArray<SerializedColumnsSource>): CollectionHandle;
|
|
84
|
+
|
|
85
|
+
/** Whether the collection currently exposes zero columns. */
|
|
86
|
+
isEmpty(handle: CollectionHandle): boolean;
|
|
87
|
+
|
|
88
|
+
/** Whether enumeration is finalised across every contributing source. */
|
|
89
|
+
isFinal(handle: CollectionHandle): boolean;
|
|
90
|
+
|
|
91
|
+
/** Canonical id list for the columns visible through this collection. */
|
|
92
|
+
getColumns(handle: CollectionHandle): ColumnUniversalId[];
|
|
93
|
+
|
|
94
|
+
/** Append one or more sources and return a fresh collection handle. */
|
|
95
|
+
addSource(
|
|
96
|
+
handle: CollectionHandle,
|
|
97
|
+
sources: ReadonlyArray<SerializedColumnsSource>,
|
|
98
|
+
): CollectionHandle;
|
|
99
|
+
|
|
100
|
+
/** Anchored/selector-driven discovery. Returns a fresh handle. */
|
|
101
|
+
discover(handle: CollectionHandle, options: ColumnsDiscoverOptions): CollectionHandle;
|
|
102
|
+
|
|
103
|
+
/** Selector-only filter (no anchor traversal). Returns a fresh handle. */
|
|
104
|
+
filter(handle: CollectionHandle, options: ColumnsFilterOptions): CollectionHandle;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Synchronous host-side driver for `ColumnsCollection` operations. All
|
|
109
|
+
* collection state lives on the host side, addressable through opaque
|
|
110
|
+
* {@link CollectionHandle}s. Every handle-minting method returns a
|
|
111
|
+
* {@link PoolEntry} so callers can wire the refcount into their own
|
|
112
|
+
* lifecycle; the VM bridge pins each entry to the active render ctx and
|
|
113
|
+
* forwards only the handle string to sandbox.
|
|
114
|
+
*
|
|
115
|
+
* Sandbox / UI callers consume {@link ColumnsCollectionDriverModel}
|
|
116
|
+
* instead; the bridge maps that surface onto this one by injecting
|
|
117
|
+
* {@link ColumnsCollectionDriverHost} bindings.
|
|
118
|
+
*/
|
|
119
|
+
export interface ColumnsCollectionDriver {
|
|
120
|
+
create(
|
|
121
|
+
sources: ReadonlyArray<SerializedColumnsSource>,
|
|
122
|
+
host: ColumnsCollectionDriverHost,
|
|
123
|
+
): PoolEntry<CollectionHandle>;
|
|
124
|
+
|
|
125
|
+
isEmpty(handle: CollectionHandle): boolean;
|
|
126
|
+
isFinal(handle: CollectionHandle): boolean;
|
|
127
|
+
getColumns(handle: CollectionHandle, host: ColumnsCollectionDriverHost): ColumnUniversalId[];
|
|
128
|
+
|
|
129
|
+
addSource(
|
|
130
|
+
handle: CollectionHandle,
|
|
131
|
+
sources: ReadonlyArray<SerializedColumnsSource>,
|
|
132
|
+
host: ColumnsCollectionDriverHost,
|
|
133
|
+
): PoolEntry<CollectionHandle>;
|
|
134
|
+
|
|
135
|
+
discover(
|
|
136
|
+
handle: CollectionHandle,
|
|
137
|
+
options: ColumnsDiscoverOptions,
|
|
138
|
+
host: ColumnsCollectionDriverHost,
|
|
139
|
+
): PoolEntry<CollectionHandle>;
|
|
140
|
+
|
|
141
|
+
filter(
|
|
142
|
+
handle: CollectionHandle,
|
|
143
|
+
options: ColumnsFilterOptions,
|
|
144
|
+
host: ColumnsCollectionDriverHost,
|
|
145
|
+
): PoolEntry<CollectionHandle>;
|
|
146
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { ColumnSelector, RelaxedColumnSelector } from "../../columns/column_selector";
|
|
2
|
+
import type { PlRef } from "../../ref";
|
|
3
|
+
import type { PObjectId } from "../../pool";
|
|
4
|
+
import type { PColumnSpec, AxisQualification } from "../pframe/spec";
|
|
5
|
+
import type { DiscoverColumnsConstraints } from "../pframe/spec_driver";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Axis matching behaviour applied to `discover` requests.
|
|
9
|
+
*
|
|
10
|
+
* - `enrichment` (default) — anchor axes may float over un-mapped hit axes;
|
|
11
|
+
* used by tooling that "extends" a query.
|
|
12
|
+
* - `related` — both source and hit axes may float; widest match.
|
|
13
|
+
* - `exact` — no floating, no qualifications; strict equality.
|
|
14
|
+
*/
|
|
15
|
+
export type MatchingMode = "enrichment" | "related" | "exact";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Single entry accepted by `DiscoverColumnsOptions.anchors`. All variants are
|
|
19
|
+
* trivially JSON-serialisable so the option carrier crosses the
|
|
20
|
+
* sandbox/host VM bridge unchanged.
|
|
21
|
+
*/
|
|
22
|
+
export type AnchorEntry = PlRef | PObjectId | PColumnSpec | RelaxedColumnSelector;
|
|
23
|
+
|
|
24
|
+
/** Qualifications needed for both already-integrated anchor columns and the hit column. */
|
|
25
|
+
export interface MatchQualifications {
|
|
26
|
+
/** Qualifications for already-integrated anchor columns */
|
|
27
|
+
readonly forQueries?: Record<PObjectId, AxisQualification[]>;
|
|
28
|
+
/** Qualifications for the hit column. */
|
|
29
|
+
readonly forHit?: AxisQualification[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options object accepted by sandbox `discoverColumns()` and by the host
|
|
34
|
+
* `ColumnsCollectionDriver.discover` / `.filter` methods. Pure JSON shape —
|
|
35
|
+
* no class instances, no closures.
|
|
36
|
+
*/
|
|
37
|
+
export interface DiscoverColumnsOptions {
|
|
38
|
+
/** Include columns matching these selectors. If omitted, includes all. */
|
|
39
|
+
include?: ColumnSelector;
|
|
40
|
+
/** Exclude columns matching these selectors. */
|
|
41
|
+
exclude?: ColumnSelector;
|
|
42
|
+
/** Axis matching behavior. Default: 'enrichment'. Ignored if no anchors. */
|
|
43
|
+
mode?: MatchingMode;
|
|
44
|
+
/** Anchors enable axis-aware discovery + linker traversal. */
|
|
45
|
+
// @todo: migrate to array<AnchorEntry>
|
|
46
|
+
anchors?: Record<string, AnchorEntry>;
|
|
47
|
+
/** Maximum linker hops. Default: 4 when anchors present, 0 otherwise. */
|
|
48
|
+
maxHops?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Options accepted by `ColumnsCollection.discover` / driver `.discover`.
|
|
53
|
+
* Traversal scope (`mode`, `maxHops`) must be specified explicitly — the
|
|
54
|
+
* defaults from {@link DiscoverColumnsOptions} are intentionally surfaced as
|
|
55
|
+
* required choices at the discovery entrypoint.
|
|
56
|
+
*/
|
|
57
|
+
export type ColumnsDiscoverOptions = DiscoverColumnsOptions;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Options accepted by `ColumnsCollection.filter` / driver `.filter`. Traversal
|
|
61
|
+
* scope is fixed by the source collection, so `mode` / `maxHops` are not part
|
|
62
|
+
* of the filter surface — only `include` / `exclude` / `anchors`.
|
|
63
|
+
*/
|
|
64
|
+
export type ColumnsFilterOptions = Omit<DiscoverColumnsOptions, "mode" | "maxHops">;
|
|
65
|
+
|
|
66
|
+
/** Translate a {@link MatchingMode} into the boolean-flag form the spec driver consumes. */
|
|
67
|
+
export function matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {
|
|
68
|
+
switch (mode) {
|
|
69
|
+
case "enrichment":
|
|
70
|
+
return {
|
|
71
|
+
allowFloatingSourceAxes: true,
|
|
72
|
+
allowFloatingHitAxes: false,
|
|
73
|
+
allowSourceQualifications: true,
|
|
74
|
+
allowHitQualifications: true,
|
|
75
|
+
};
|
|
76
|
+
case "related":
|
|
77
|
+
return {
|
|
78
|
+
allowFloatingSourceAxes: true,
|
|
79
|
+
allowFloatingHitAxes: true,
|
|
80
|
+
allowSourceQualifications: true,
|
|
81
|
+
allowHitQualifications: true,
|
|
82
|
+
};
|
|
83
|
+
case "exact":
|
|
84
|
+
return {
|
|
85
|
+
allowFloatingSourceAxes: false,
|
|
86
|
+
allowFloatingHitAxes: false,
|
|
87
|
+
allowSourceQualifications: false,
|
|
88
|
+
allowHitQualifications: false,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/drivers/index.ts
CHANGED
|
@@ -1169,3 +1169,27 @@ export interface QueryTransformColumns<Q, E, SO> {
|
|
|
1169
1169
|
/** Derived columns to compute (at least one). */
|
|
1170
1170
|
columns: [TransformColumnEntry<E, SO>, ...TransformColumnEntry<E, SO>[]];
|
|
1171
1171
|
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* Spec-override query operation — client-side-only structural node.
|
|
1175
|
+
*
|
|
1176
|
+
* Overlays a {@link SpecOverrides} patch on top of the inner query's spec.
|
|
1177
|
+
* Carries no topological change — it is collapsed at the host boundary
|
|
1178
|
+
* (`resolvePColumn`) before the query reaches pframe-engine. The engine
|
|
1179
|
+
* never sees this node.
|
|
1180
|
+
*
|
|
1181
|
+
* Emitted by `ColumnOverriddenRecipe.getQuery()`; the only currently
|
|
1182
|
+
* supported shape is `specOverride{ input: <plain column ref>, override }`
|
|
1183
|
+
* (i.e. `Overridden<Lazy>`). More complex projections under Overridden are
|
|
1184
|
+
* a future engine work item.
|
|
1185
|
+
*
|
|
1186
|
+
* @template Q - Input query type
|
|
1187
|
+
* @template SO - Spec override type
|
|
1188
|
+
*/
|
|
1189
|
+
export interface QuerySpecOverride<Q, SO> {
|
|
1190
|
+
type: "specOverride";
|
|
1191
|
+
/** Input query whose spec is to be overridden. */
|
|
1192
|
+
input: Q;
|
|
1193
|
+
/** Spec override patch to overlay on the inner spec. */
|
|
1194
|
+
override: SO;
|
|
1195
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PObjectId } from "../../../pool";
|
|
2
|
+
import type { ColumnUniversalId } from "../spec/ids";
|
|
2
3
|
import type {
|
|
3
4
|
ExprAxisRef,
|
|
4
5
|
ExprCast,
|
|
@@ -28,10 +29,12 @@ import type {
|
|
|
28
29
|
QuerySliceAxes,
|
|
29
30
|
QuerySort,
|
|
30
31
|
QuerySparseToDenseColumn,
|
|
32
|
+
QuerySpecOverride,
|
|
31
33
|
QuerySymmetricJoin,
|
|
32
34
|
QueryTransformColumns,
|
|
33
35
|
} from "./query_common";
|
|
34
36
|
import type { Domain, PColumnIdAndSpec, SingleAxisSelector } from "../spec";
|
|
37
|
+
import type { SpecOverrides } from "../spec/overridden";
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
40
|
* Join entry for spec-layer queries — the base join entry extended with
|
|
@@ -43,8 +46,8 @@ import type { Domain, PColumnIdAndSpec, SingleAxisSelector } from "../spec";
|
|
|
43
46
|
* qualifications: [{ axis: { name: 'sample' }, contextDomain: { ... } }]
|
|
44
47
|
* }
|
|
45
48
|
*/
|
|
46
|
-
export type SpecQueryJoinEntry<C =
|
|
47
|
-
qualifications?: {
|
|
49
|
+
export type SpecQueryJoinEntry<C = ColumnUniversalId> = QueryJoinEntry<SpecQuery<C>> & {
|
|
50
|
+
qualifications?: readonly {
|
|
48
51
|
/** Axis to qualify. */
|
|
49
52
|
axis: SingleAxisSelector;
|
|
50
53
|
/** Additional domain constraints for this axis. */
|
|
@@ -53,46 +56,54 @@ export type SpecQueryJoinEntry<C = PObjectId> = QueryJoinEntry<SpecQuery<C>> & {
|
|
|
53
56
|
};
|
|
54
57
|
|
|
55
58
|
/** @see QueryColumn */
|
|
56
|
-
export type SpecQueryColumn<C =
|
|
59
|
+
export type SpecQueryColumn<C = ColumnUniversalId> = QueryColumn<C>;
|
|
57
60
|
/** @see QueryInlineColumn */
|
|
58
61
|
export type SpecQueryInlineColumn = QueryInlineColumn<PColumnIdAndSpec>;
|
|
59
62
|
/** @see QuerySparseToDenseColumn */
|
|
60
|
-
export type SpecQuerySparseToDenseColumn<C =
|
|
63
|
+
export type SpecQuerySparseToDenseColumn<C = ColumnUniversalId> = QuerySparseToDenseColumn<
|
|
61
64
|
C,
|
|
62
65
|
SingleAxisSelector,
|
|
63
66
|
PColumnIdAndSpec
|
|
64
67
|
>;
|
|
65
68
|
/** @see QuerySymmetricJoin */
|
|
66
|
-
export type SpecQuerySymmetricJoin<C =
|
|
69
|
+
export type SpecQuerySymmetricJoin<C = ColumnUniversalId> = QuerySymmetricJoin<
|
|
70
|
+
SpecQueryJoinEntry<C>
|
|
71
|
+
>;
|
|
67
72
|
/** @see QueryOuterJoin */
|
|
68
|
-
export type SpecQueryOuterJoin<C =
|
|
69
|
-
/**
|
|
70
|
-
* Linker side of a spec-layer linker-join.
|
|
71
|
-
*
|
|
72
|
-
* At the spec layer the linker is just a column reference — integration artifacts
|
|
73
|
-
* (axes mapping, one-side indices) are derived during spec→data conversion.
|
|
74
|
-
*/
|
|
75
|
-
export type SpecQueryLinkerJoinLinker<C = PObjectId> = {
|
|
76
|
-
/** Linker column reference. */
|
|
77
|
-
column: C;
|
|
78
|
-
};
|
|
73
|
+
export type SpecQueryOuterJoin<C = ColumnUniversalId> = QueryOuterJoin<SpecQueryJoinEntry<C>>;
|
|
79
74
|
/** @see QueryLinkerJoin */
|
|
80
|
-
export type SpecQueryLinkerJoin<C =
|
|
81
|
-
|
|
75
|
+
export type SpecQueryLinkerJoin<C = ColumnUniversalId> = QueryLinkerJoin<
|
|
76
|
+
SpecQuery<C>,
|
|
82
77
|
SpecQueryJoinEntry<C>
|
|
83
78
|
>;
|
|
84
79
|
/** @see QuerySliceAxes */
|
|
85
|
-
export type SpecQuerySliceAxes<C =
|
|
80
|
+
export type SpecQuerySliceAxes<C = ColumnUniversalId> = QuerySliceAxes<
|
|
81
|
+
SpecQuery<C>,
|
|
82
|
+
SingleAxisSelector
|
|
83
|
+
>;
|
|
86
84
|
/** @see QuerySort */
|
|
87
|
-
export type SpecQuerySort<C =
|
|
85
|
+
export type SpecQuerySort<C = ColumnUniversalId> = QuerySort<SpecQuery<C>, SpecQueryExpression>;
|
|
88
86
|
/** @see QueryFilter */
|
|
89
|
-
export type SpecQueryFilter<C =
|
|
87
|
+
export type SpecQueryFilter<C = ColumnUniversalId> = QueryFilter<
|
|
88
|
+
SpecQuery<C>,
|
|
89
|
+
SpecQueryBooleanExpression
|
|
90
|
+
>;
|
|
90
91
|
/** @see QueryTransformColumns */
|
|
91
|
-
export type SpecQueryTransformColumns<C =
|
|
92
|
+
export type SpecQueryTransformColumns<C = ColumnUniversalId> = QueryTransformColumns<
|
|
92
93
|
SpecQuery<C>,
|
|
93
94
|
SpecQueryExpression,
|
|
94
95
|
PColumnIdAndSpec
|
|
95
96
|
>;
|
|
97
|
+
/**
|
|
98
|
+
* Client-side spec-override node — collapsed at the host boundary, never
|
|
99
|
+
* sent to pframe-engine.
|
|
100
|
+
*
|
|
101
|
+
* @see QuerySpecOverride
|
|
102
|
+
*/
|
|
103
|
+
export type SpecQuerySpecOverride<C = ColumnUniversalId> = QuerySpecOverride<
|
|
104
|
+
SpecQuery<C>,
|
|
105
|
+
SpecOverrides
|
|
106
|
+
>;
|
|
96
107
|
|
|
97
108
|
/**
|
|
98
109
|
* Union of all spec layer query types.
|
|
@@ -108,8 +119,9 @@ export type SpecQueryTransformColumns<C = PObjectId> = QueryTransformColumns<
|
|
|
108
119
|
* - Leaf nodes: column, inlineColumn, sparseToDenseColumn
|
|
109
120
|
* - Join operations: innerJoin, fullJoin, outerJoin, linkerJoin
|
|
110
121
|
* - Transformations: sliceAxes, sort, filter, transformColumns
|
|
122
|
+
* - Client-side overlays: specOverride (collapsed before reaching the engine)
|
|
111
123
|
*/
|
|
112
|
-
export type SpecQuery<C =
|
|
124
|
+
export type SpecQuery<C = ColumnUniversalId> =
|
|
113
125
|
| SpecQueryColumn<C>
|
|
114
126
|
| SpecQueryInlineColumn
|
|
115
127
|
| SpecQuerySparseToDenseColumn<C>
|
|
@@ -119,12 +131,13 @@ export type SpecQuery<C = PObjectId> =
|
|
|
119
131
|
| SpecQuerySliceAxes<C>
|
|
120
132
|
| SpecQuerySort<C>
|
|
121
133
|
| SpecQueryFilter<C>
|
|
122
|
-
| SpecQueryTransformColumns<C
|
|
134
|
+
| SpecQueryTransformColumns<C>
|
|
135
|
+
| SpecQuerySpecOverride<C>;
|
|
123
136
|
|
|
124
137
|
/** @see ExprAxisRef */
|
|
125
138
|
export type SpecExprAxisRef = ExprAxisRef<SingleAxisSelector>;
|
|
126
139
|
/** @see ExprColumnRef */
|
|
127
|
-
export type SpecExprColumnRef = ExprColumnRef<
|
|
140
|
+
export type SpecExprColumnRef = ExprColumnRef<ColumnUniversalId>;
|
|
128
141
|
|
|
129
142
|
export type SpecQueryExpression =
|
|
130
143
|
| SpecExprColumnRef
|
|
@@ -85,13 +85,13 @@ describe("traverseQuerySpec", () => {
|
|
|
85
85
|
it("transforms columns inside linkerJoin", () => {
|
|
86
86
|
const q: Q = {
|
|
87
87
|
type: "linkerJoin",
|
|
88
|
-
linker:
|
|
88
|
+
linker: col("l"),
|
|
89
89
|
secondary: [entry(col("a")), entry(col("b"))],
|
|
90
90
|
};
|
|
91
91
|
const result = traverseQuerySpec(q, { column: (c) => c.toUpperCase() });
|
|
92
92
|
expect(result).toEqual({
|
|
93
93
|
type: "linkerJoin",
|
|
94
|
-
linker: { column: "L" },
|
|
94
|
+
linker: { type: "column", column: "L" },
|
|
95
95
|
secondary: [entry({ type: "column", column: "A" }), entry({ type: "column", column: "B" })],
|
|
96
96
|
});
|
|
97
97
|
});
|
|
@@ -180,7 +180,7 @@ describe("mapSpecQueryColumns", () => {
|
|
|
180
180
|
primary: entry(col("a")),
|
|
181
181
|
secondary: [entry(col("b"))],
|
|
182
182
|
};
|
|
183
|
-
const result = mapSpecQueryColumns(q, (c) => c.toUpperCase());
|
|
183
|
+
const result = mapSpecQueryColumns(q, { column: (c) => c.toUpperCase() });
|
|
184
184
|
expect(collectSpecQueryColumns(result)).toEqual(["A", "B"]);
|
|
185
185
|
});
|
|
186
186
|
});
|
|
@@ -229,7 +229,7 @@ describe("collectSpecQueryColumns", () => {
|
|
|
229
229
|
it("collects linker and secondary columns from linkerJoin", () => {
|
|
230
230
|
const q: Q = {
|
|
231
231
|
type: "linkerJoin",
|
|
232
|
-
linker:
|
|
232
|
+
linker: col("l"),
|
|
233
233
|
secondary: [entry(col("a")), entry(col("b"))],
|
|
234
234
|
};
|
|
235
235
|
expect(collectSpecQueryColumns(q)).toEqual(["l", "a", "b"]);
|
|
@@ -263,13 +263,13 @@ describe("sortSpecQuery", () => {
|
|
|
263
263
|
it("sorts linkerJoin secondary entries (linker column unchanged)", () => {
|
|
264
264
|
const q: SpecQuery = {
|
|
265
265
|
type: "linkerJoin",
|
|
266
|
-
linker:
|
|
266
|
+
linker: pcol("l"),
|
|
267
267
|
secondary: [pentry(pcol("c")), pentry(pcol("a")), pentry(pcol("b"))],
|
|
268
268
|
};
|
|
269
269
|
const result = sortSpecQuery(q);
|
|
270
270
|
expect(result).toEqual({
|
|
271
271
|
type: "linkerJoin",
|
|
272
|
-
linker:
|
|
272
|
+
linker: pcol("l"),
|
|
273
273
|
secondary: [pentry(pcol("a")), pentry(pcol("b")), pentry(pcol("c"))],
|
|
274
274
|
});
|
|
275
275
|
});
|
|
@@ -79,17 +79,25 @@ export function traverseQuerySpec<C1, C2>(
|
|
|
79
79
|
secondary: query.secondary.map(traverseEntry),
|
|
80
80
|
};
|
|
81
81
|
break;
|
|
82
|
-
case "linkerJoin":
|
|
82
|
+
case "linkerJoin": {
|
|
83
|
+
// Back-compat: pre-#c7309fc8 blocks emit `linker` as `{ column }` without
|
|
84
|
+
// a `type` — tag it as a `column` node so recursion handles it normally.
|
|
85
|
+
const linker =
|
|
86
|
+
"type" in query.linker
|
|
87
|
+
? query.linker
|
|
88
|
+
: ({ type: "column", column: (query.linker as { column: C1 }).column } as SpecQuery<C1>);
|
|
83
89
|
result = {
|
|
84
90
|
...query,
|
|
85
|
-
linker:
|
|
91
|
+
linker: traverseQuerySpec(linker, visitor),
|
|
86
92
|
secondary: query.secondary.map(traverseEntry),
|
|
87
93
|
};
|
|
88
94
|
break;
|
|
95
|
+
}
|
|
89
96
|
case "filter":
|
|
90
97
|
case "sort":
|
|
91
98
|
case "sliceAxes":
|
|
92
99
|
case "transformColumns":
|
|
100
|
+
case "specOverride":
|
|
93
101
|
result = { ...query, input: traverseQuerySpec(query.input, visitor) };
|
|
94
102
|
break;
|
|
95
103
|
default:
|
|
@@ -102,9 +110,16 @@ export function traverseQuerySpec<C1, C2>(
|
|
|
102
110
|
/** Recursively maps all column references in a SpecQuery tree. */
|
|
103
111
|
export function mapSpecQueryColumns<C1, C2>(
|
|
104
112
|
query: SpecQuery<C1>,
|
|
105
|
-
|
|
113
|
+
visitor: {
|
|
114
|
+
/** Transform column references in leaf nodes (column, sparseToDenseColumn). */
|
|
115
|
+
column: (c: C1) => C2;
|
|
116
|
+
/** Visit a node after its children have been traversed. */
|
|
117
|
+
node?: (node: SpecQuery<C2>) => SpecQuery<C2>;
|
|
118
|
+
/** Visit a join entry after its inner query has been traversed. */
|
|
119
|
+
joinEntry?: (entry: SpecQueryJoinEntry<C2>) => SpecQueryJoinEntry<C2>;
|
|
120
|
+
},
|
|
106
121
|
): SpecQuery<C2> {
|
|
107
|
-
return traverseQuerySpec(query,
|
|
122
|
+
return traverseQuerySpec(query, visitor);
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
/** Collects all column references from a SpecQuery tree. */
|
|
@@ -227,9 +242,8 @@ function cmpQuerySpec(lhs: SpecQuery, rhs: SpecQuery): number {
|
|
|
227
242
|
}
|
|
228
243
|
case "linkerJoin": {
|
|
229
244
|
const rhsLinker = rhs as typeof lhs;
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
245
|
+
const cmp = cmpQuerySpec(lhs.linker, rhsLinker.linker);
|
|
246
|
+
if (cmp !== 0) return cmp;
|
|
233
247
|
if (lhs.secondary.length !== rhsLinker.secondary.length) {
|
|
234
248
|
return lhs.secondary.length - rhsLinker.secondary.length;
|
|
235
249
|
}
|
|
@@ -245,6 +259,12 @@ function cmpQuerySpec(lhs: SpecQuery, rhs: SpecQuery): number {
|
|
|
245
259
|
return cmpQuerySpec(lhs.input, (rhs as typeof lhs).input);
|
|
246
260
|
case "filter":
|
|
247
261
|
return cmpQuerySpec(lhs.input, (rhs as typeof lhs).input);
|
|
262
|
+
case "specOverride": {
|
|
263
|
+
const rhsSo = rhs as typeof lhs;
|
|
264
|
+
const cmp = cmpQuerySpec(lhs.input, rhsSo.input);
|
|
265
|
+
if (cmp !== 0) return cmp;
|
|
266
|
+
return canonicalizeJson(lhs.override).localeCompare(canonicalizeJson(rhsSo.override));
|
|
267
|
+
}
|
|
248
268
|
case "transformColumns": {
|
|
249
269
|
const rhsTc = rhs as typeof lhs;
|
|
250
270
|
const cmp = cmpQuerySpec(lhs.input, rhsTc.input);
|