@milaboratories/pl-model-common 1.26.0 → 1.27.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/drivers/index.d.ts +2 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/pframe/index.d.ts +1 -1
- package/dist/drivers/pframe/index.js +1 -1
- package/dist/drivers/pframe/linker_columns.cjs +2 -5
- package/dist/drivers/pframe/linker_columns.cjs.map +1 -1
- package/dist/drivers/pframe/linker_columns.js +2 -5
- package/dist/drivers/pframe/linker_columns.js.map +1 -1
- package/dist/drivers/pframe/spec/anchored.cjs.map +1 -1
- package/dist/drivers/pframe/spec/anchored.js.map +1 -1
- package/dist/drivers/pframe/spec/index.d.ts +1 -1
- package/dist/drivers/pframe/spec/index.js +1 -1
- package/dist/drivers/pframe/spec/selectors.cjs +2 -2
- package/dist/drivers/pframe/spec/selectors.cjs.map +1 -1
- package/dist/drivers/pframe/spec/selectors.d.ts +12 -6
- package/dist/drivers/pframe/spec/selectors.js +2 -2
- package/dist/drivers/pframe/spec/selectors.js.map +1 -1
- package/dist/drivers/pspec.d.ts +127 -0
- package/dist/index.cjs +4 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -2
- package/dist/resource_types.cjs +53 -0
- package/dist/resource_types.cjs.map +1 -0
- package/dist/resource_types.d.ts +50 -0
- package/dist/resource_types.js +51 -0
- package/dist/resource_types.js.map +1 -0
- package/package.json +5 -4
- package/src/common_types.ts +0 -1
- package/src/drivers/index.ts +1 -0
- package/src/drivers/pframe/linker_columns.test.ts +22 -3
- package/src/drivers/pframe/linker_columns.ts +2 -2
- package/src/drivers/pframe/spec/anchored.ts +2 -2
- package/src/drivers/pframe/spec/selectors.ts +11 -5
- package/src/drivers/pframe/type_util.ts +0 -1
- package/src/drivers/pspec.ts +143 -0
- package/src/index.ts +1 -0
- package/src/resource_types.ts +47 -0
|
@@ -98,7 +98,7 @@ describe("Linker columns", () => {
|
|
|
98
98
|
expect(linkers.map((item) => item.spec.name).sort()).toEqual(params.expected);
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
-
testCase({ from: [axis2], to: [axis3], expected: [
|
|
101
|
+
testCase({ from: [axis2], to: [axis3], expected: [] });
|
|
102
102
|
testCase({ from: [axis1], to: [axis2], expected: ["c12"] });
|
|
103
103
|
testCase({ from: [axis1], to: [axis4], expected: [] });
|
|
104
104
|
});
|
|
@@ -239,11 +239,13 @@ describe("Linker columns", () => {
|
|
|
239
239
|
|
|
240
240
|
const linkersMap = LinkerMap.fromColumns([linker1, linker2]);
|
|
241
241
|
|
|
242
|
+
// Forward-only: from group2 we only reach group3 (no back edge to group1)
|
|
242
243
|
expect(
|
|
243
244
|
new Set(
|
|
244
245
|
linkersMap.getReachableByLinkersAxesFromAxesNormalized(group2Normalized).map((a) => a.name),
|
|
245
246
|
),
|
|
246
|
-
).toEqual(new Set([...
|
|
247
|
+
).toEqual(new Set([...group3].map((a) => a.name)));
|
|
248
|
+
// Non-root axes (axisDn, axisBn) don't match linker map keys, so no forward reachability
|
|
247
249
|
expect(linkersMap.getReachableByLinkersAxesFromAxesNormalized([axisDn])).toEqual([]);
|
|
248
250
|
expect(linkersMap.getReachableByLinkersAxesFromAxesNormalized([axisBn])).toEqual([]);
|
|
249
251
|
});
|
|
@@ -282,7 +284,7 @@ describe("Linker columns", () => {
|
|
|
282
284
|
getNormalizedAxesList([axisA, axisB, axisC, axisE]),
|
|
283
285
|
)
|
|
284
286
|
.map((v) => v.name),
|
|
285
|
-
).toEqual(["a", "b", "e"]);
|
|
287
|
+
).toEqual(["a", "b", "c", "e"]);
|
|
286
288
|
|
|
287
289
|
expect(
|
|
288
290
|
linkerMap
|
|
@@ -290,4 +292,21 @@ describe("Linker columns", () => {
|
|
|
290
292
|
.map((v) => v.name),
|
|
291
293
|
).toEqual(["a", "b", "c", "e"]);
|
|
292
294
|
});
|
|
295
|
+
|
|
296
|
+
test("getReachableByLinkersAxesFromAxes", () => {
|
|
297
|
+
const axisA = makeTestAxis({ name: "a" });
|
|
298
|
+
const axisB = makeTestAxis({ name: "b" });
|
|
299
|
+
const axisC = makeTestAxis({ name: "c" });
|
|
300
|
+
const axisD = makeTestAxis({ name: "d" });
|
|
301
|
+
const linkerMap = LinkerMap.fromColumns([
|
|
302
|
+
makeLinkerColumn({ name: "linker1", from: [axisA], to: [axisB] }),
|
|
303
|
+
makeLinkerColumn({ name: "linker2", from: [axisB], to: [axisC] }),
|
|
304
|
+
makeLinkerColumn({ name: "linker3", from: [axisC], to: [axisD] }),
|
|
305
|
+
]);
|
|
306
|
+
|
|
307
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([axisA])).toEqual(
|
|
308
|
+
getNormalizedAxesList([axisB, axisC, axisD]),
|
|
309
|
+
);
|
|
310
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([axisD])).toEqual([]);
|
|
311
|
+
});
|
|
293
312
|
});
|
|
@@ -89,7 +89,6 @@ export class LinkerMap implements LinkersData {
|
|
|
89
89
|
for (const [keyLeft] of leftKeyVariants) {
|
|
90
90
|
for (const [keyRight] of rightKeyVariants) {
|
|
91
91
|
result.get(keyLeft)?.linkWith.set(keyRight, linker);
|
|
92
|
-
result.get(keyRight)?.linkWith.set(keyLeft, linker);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
}
|
|
@@ -138,7 +137,8 @@ export class LinkerMap implements LinkersData {
|
|
|
138
137
|
current = previous[current];
|
|
139
138
|
}
|
|
140
139
|
ids.push(current);
|
|
141
|
-
|
|
140
|
+
// Edge (previous[id] -> id) is stored at the "from" node in one-directional map
|
|
141
|
+
return ids.map((id: LinkerKey) => this.data.get(previous[id])!.linkWith.get(id)!);
|
|
142
142
|
} else if (!visited.has(availableId)) {
|
|
143
143
|
next.add(availableId);
|
|
144
144
|
visited.add(availableId);
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
AnchorAxisRefByIdx,
|
|
9
9
|
AnchoredPColumnId,
|
|
10
10
|
AnchoredPColumnSelector,
|
|
11
|
-
|
|
11
|
+
LegacyAxisSelector,
|
|
12
12
|
PColumnSelector,
|
|
13
13
|
} from "./selectors";
|
|
14
14
|
import type { AxisId, PColumnSpec } from "./spec";
|
|
@@ -323,7 +323,7 @@ export function resolveAnchors(
|
|
|
323
323
|
function resolveAxisReference(
|
|
324
324
|
anchors: Record<string, PColumnSpec>,
|
|
325
325
|
axisRef: AAxisSelector,
|
|
326
|
-
):
|
|
326
|
+
): LegacyAxisSelector {
|
|
327
327
|
if (!isAnchorAxisRef(axisRef)) return axisRef;
|
|
328
328
|
|
|
329
329
|
// It's an anchored reference
|
|
@@ -12,8 +12,14 @@ import { getAxisId } from "./spec";
|
|
|
12
12
|
*
|
|
13
13
|
* This interface is used in various selection and matching operations
|
|
14
14
|
* throughout the PFrame system, such as column queries and axis lookups.
|
|
15
|
+
*
|
|
16
|
+
* @deprecated This selector is part of the legacy column matching API.
|
|
17
|
+
* The new Columns API (see sdk/model/src/columns/) now handles column and axis
|
|
18
|
+
* selection via {@link AxisSelector} and {@link ColumnSelector}, providing
|
|
19
|
+
* stricter matching semantics (StringMatcher-based) and a unified approach
|
|
20
|
+
* to working with columns, including domain and annotation matching.
|
|
15
21
|
*/
|
|
16
|
-
export interface
|
|
22
|
+
export interface LegacyAxisSelector {
|
|
17
23
|
/**
|
|
18
24
|
* Optional value type to match against.
|
|
19
25
|
* When specified, only axes with this exact type will match.
|
|
@@ -94,7 +100,7 @@ export type ADomain = string | AnchorDomainRef;
|
|
|
94
100
|
* Axis identifier that can be either a direct AxisId or a reference to an axis through an anchor
|
|
95
101
|
* Allows referring to axes in a way that can be resolved in different contexts
|
|
96
102
|
*/
|
|
97
|
-
export type AAxisSelector =
|
|
103
|
+
export type AAxisSelector = LegacyAxisSelector | AnchorAxisRef;
|
|
98
104
|
|
|
99
105
|
/**
|
|
100
106
|
* Match resolution strategy for PColumns
|
|
@@ -144,7 +150,7 @@ export interface PColumnSelector extends AnchoredPColumnSelector {
|
|
|
144
150
|
domain?: Record<string, string>;
|
|
145
151
|
contextDomainAnchor?: never;
|
|
146
152
|
contextDomain?: Record<string, string>;
|
|
147
|
-
axes?:
|
|
153
|
+
axes?: LegacyAxisSelector[];
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
/**
|
|
@@ -187,7 +193,7 @@ export function isAnchoredPColumnId(id: unknown): id is AnchoredPColumnId {
|
|
|
187
193
|
* @param axis - The AxisId to check against the selector
|
|
188
194
|
* @returns true if the AxisId matches all specified criteria in the selector, false otherwise
|
|
189
195
|
*/
|
|
190
|
-
export function matchAxis(selector:
|
|
196
|
+
export function matchAxis(selector: LegacyAxisSelector, axis: AxisId): boolean {
|
|
191
197
|
// Match name if specified
|
|
192
198
|
if (selector.name !== undefined && selector.name !== axis.name) return false;
|
|
193
199
|
|
|
@@ -298,7 +304,7 @@ export function matchPColumn(pcolumn: PColumnSpec, selector: PColumnSelector): b
|
|
|
298
304
|
* or an array of PColumnSelectors, or a single PColumnSelector
|
|
299
305
|
* @returns A function that takes a PColumnSpec and returns a boolean
|
|
300
306
|
*/
|
|
301
|
-
export function
|
|
307
|
+
export function legacyColumnSelectorsToPredicate(
|
|
302
308
|
predicateOrSelectors: PColumnSelector | PColumnSelector[],
|
|
303
309
|
): (spec: PObjectSpec) => boolean {
|
|
304
310
|
if (Array.isArray(predicateOrSelectors))
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { Branded } from "@milaboratories/helpers";
|
|
2
|
+
import type {
|
|
3
|
+
ValueType,
|
|
4
|
+
SingleAxisSelector,
|
|
5
|
+
AxisSpec,
|
|
6
|
+
PColumnIdAndSpec,
|
|
7
|
+
PColumnSpec,
|
|
8
|
+
} from "./pframe";
|
|
9
|
+
|
|
10
|
+
// --- Discover columns types (duplicated from middle-layer internal_api) ---
|
|
11
|
+
|
|
12
|
+
/** Matches a string value either exactly or by regex pattern */
|
|
13
|
+
export type StringMatcher = { type: "exact"; value: string } | { type: "regex"; value: string };
|
|
14
|
+
|
|
15
|
+
/** Map of key to array of string matchers (OR-ed per key, AND-ed across keys) */
|
|
16
|
+
export type MatcherMap = Record<string, StringMatcher[]>;
|
|
17
|
+
|
|
18
|
+
/** Selector for matching axes by various criteria */
|
|
19
|
+
export interface MultiAxisSelector {
|
|
20
|
+
/** Match any of the axis types listed here */
|
|
21
|
+
readonly type?: ValueType[];
|
|
22
|
+
/** Match any of the axis names listed here */
|
|
23
|
+
readonly name?: StringMatcher[];
|
|
24
|
+
/** Match requires all the domains listed here */
|
|
25
|
+
readonly domain?: MatcherMap;
|
|
26
|
+
/** Match requires all the context domains listed here */
|
|
27
|
+
readonly contextDomain?: MatcherMap;
|
|
28
|
+
/** Match requires all the annotations listed here */
|
|
29
|
+
readonly annotations?: MatcherMap;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Column selector for discover columns request, matching columns by various criteria.
|
|
33
|
+
* Multiple selectors are OR-ed: a column matches if it satisfies any selector. */
|
|
34
|
+
export interface MultiColumnSelector {
|
|
35
|
+
/** Match any of the value types listed here */
|
|
36
|
+
readonly type?: ValueType[];
|
|
37
|
+
/** Match any of the names listed here */
|
|
38
|
+
readonly name?: StringMatcher[];
|
|
39
|
+
/** Match requires all the domains listed here */
|
|
40
|
+
readonly domain?: MatcherMap;
|
|
41
|
+
/** Match requires all the context domains listed here */
|
|
42
|
+
readonly contextDomain?: MatcherMap;
|
|
43
|
+
/** Match requires all the annotations listed here */
|
|
44
|
+
readonly annotations?: MatcherMap;
|
|
45
|
+
/** Match any of the axis selectors listed here */
|
|
46
|
+
readonly axes?: MultiAxisSelector[];
|
|
47
|
+
/** When true (default), allows matching if only a subset of axes match */
|
|
48
|
+
readonly partialAxesMatch?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Qualification applied to a single axis to make it compatible during integration. */
|
|
52
|
+
export interface AxisQualification {
|
|
53
|
+
/** Axis selector identifying which axis is qualified. */
|
|
54
|
+
readonly axis: SingleAxisSelector;
|
|
55
|
+
/** Additional context domain entries applied to the axis. */
|
|
56
|
+
readonly contextDomain: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Qualifications needed for both query (already-integrated) columns and the hit column. */
|
|
60
|
+
export interface ColumnAxesWithQualifications {
|
|
61
|
+
/** Already integrated (query) columns with their qualifications. */
|
|
62
|
+
axesSpec: AxisSpec[];
|
|
63
|
+
/** Qualifications for each already integrated (query) column. */
|
|
64
|
+
qualifications: AxisQualification[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Fine-grained constraints controlling axes matching and qualification behavior */
|
|
68
|
+
export interface DiscoverColumnsConstraints {
|
|
69
|
+
/** Allow source (query) axes that have no match in the hit column */
|
|
70
|
+
allowFloatingSourceAxes: boolean;
|
|
71
|
+
/** Allow hit column axes that have no match in the source (query) */
|
|
72
|
+
allowFloatingHitAxes: boolean;
|
|
73
|
+
/** Allow source (query) axes to be qualified (contextDomain extended) */
|
|
74
|
+
allowSourceQualifications: boolean;
|
|
75
|
+
/** Allow hit column axes to be qualified (contextDomain extended) */
|
|
76
|
+
allowHitQualifications: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Request for discovering columns compatible with a given axes integration */
|
|
80
|
+
export interface DiscoverColumnsRequest {
|
|
81
|
+
/** Column filters (OR-ed); empty array matches all columns */
|
|
82
|
+
columnFilter?: MultiColumnSelector[];
|
|
83
|
+
/** Already integrated axes with qualifications */
|
|
84
|
+
axes: ColumnAxesWithQualifications[];
|
|
85
|
+
/** Constraints controlling axes matching and qualification behavior */
|
|
86
|
+
constraints: DiscoverColumnsConstraints;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Qualifications info for a discover columns response mapping variant */
|
|
90
|
+
export interface DiscoverColumnsResponseQualifications {
|
|
91
|
+
/** Qualifications for each query (already-integrated) column set */
|
|
92
|
+
forQueries: AxisQualification[][];
|
|
93
|
+
/** Qualifications for the hit column */
|
|
94
|
+
forHit: AxisQualification[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** A single mapping variant describing how a hit column can be integrated */
|
|
98
|
+
export interface DiscoverColumnsMappingVariant {
|
|
99
|
+
/** Full qualifications needed for integration */
|
|
100
|
+
qualifications: DiscoverColumnsResponseQualifications;
|
|
101
|
+
/** Distinctive (minimal) qualifications needed for integration */
|
|
102
|
+
distinctiveQualifications: DiscoverColumnsResponseQualifications;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** A single hit in the discover columns response */
|
|
106
|
+
export interface DiscoverColumnsResponseHit {
|
|
107
|
+
/** The column that was found compatible */
|
|
108
|
+
hit: PColumnIdAndSpec;
|
|
109
|
+
/** Possible ways to integrate this column with the existing set */
|
|
110
|
+
mappingVariants: DiscoverColumnsMappingVariant[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Response from discover columns */
|
|
114
|
+
export interface DiscoverColumnsResponse {
|
|
115
|
+
/** Columns that could be integrated and possible ways to integrate them */
|
|
116
|
+
hits: DiscoverColumnsResponseHit[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// --- Spec driver ---
|
|
120
|
+
|
|
121
|
+
/** Handle to a spec-only PFrame (no data, synchronous operations). */
|
|
122
|
+
export type SpecFrameHandle = Branded<string, "SpecFrameHandle">;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Synchronous driver for spec-level PFrame operations.
|
|
126
|
+
*
|
|
127
|
+
* Unlike the async PFrameDriver (which works with data), this driver
|
|
128
|
+
* operates on column specifications only. All methods are synchronous
|
|
129
|
+
* because the underlying WASM PFrame computes results immediately.
|
|
130
|
+
*/
|
|
131
|
+
export interface PSpecDriver {
|
|
132
|
+
/** Create a spec-only PFrame from column specs. Returns a handle. */
|
|
133
|
+
createSpecFrame(specs: Record<string, PColumnSpec>): SpecFrameHandle;
|
|
134
|
+
|
|
135
|
+
/** Discover columns compatible with given axes integration. */
|
|
136
|
+
specFrameDiscoverColumns(
|
|
137
|
+
handle: SpecFrameHandle,
|
|
138
|
+
request: DiscoverColumnsRequest,
|
|
139
|
+
): DiscoverColumnsResponse;
|
|
140
|
+
|
|
141
|
+
/** Dispose a spec frame, freeing WASM resources. */
|
|
142
|
+
disposeSpecFrame(handle: SpecFrameHandle): void;
|
|
143
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Well-known resource type names used across the platform. */
|
|
2
|
+
export const ResourceTypeName = {
|
|
3
|
+
StreamManager: "StreamManager",
|
|
4
|
+
StdMap: "StdMap",
|
|
5
|
+
StdMapSlash: "std/map",
|
|
6
|
+
EphStdMap: "EphStdMap",
|
|
7
|
+
PFrame: "PFrame",
|
|
8
|
+
ParquetChunk: "ParquetChunk",
|
|
9
|
+
BContext: "BContext",
|
|
10
|
+
BlockPackCustom: "BlockPackCustom",
|
|
11
|
+
BinaryMap: "BinaryMap",
|
|
12
|
+
BinaryValue: "BinaryValue",
|
|
13
|
+
BlobMap: "BlobMap",
|
|
14
|
+
BResolveSingle: "BResolveSingle",
|
|
15
|
+
BResolveSingleNoResult: "BResolveSingleNoResult",
|
|
16
|
+
BQueryResult: "BQueryResult",
|
|
17
|
+
TengoTemplate: "TengoTemplate",
|
|
18
|
+
TengoLib: "TengoLib",
|
|
19
|
+
SoftwareInfo: "SoftwareInfo",
|
|
20
|
+
Dummy: "Dummy",
|
|
21
|
+
JsonResourceError: "json/resourceError",
|
|
22
|
+
JsonObject: "json/object",
|
|
23
|
+
JsonGzObject: "json-gz/object",
|
|
24
|
+
JsonString: "json/string",
|
|
25
|
+
JsonArray: "json/array",
|
|
26
|
+
JsonNumber: "json/number",
|
|
27
|
+
BContextEnd: "BContextEnd",
|
|
28
|
+
FrontendFromUrl: "Frontend/FromUrl",
|
|
29
|
+
FrontendFromFolder: "Frontend/FromFolder",
|
|
30
|
+
BObjectSpec: "BObjectSpec",
|
|
31
|
+
Blob: "Blob",
|
|
32
|
+
Null: "Null",
|
|
33
|
+
Binary: "binary",
|
|
34
|
+
LSProvider: "LSProvider",
|
|
35
|
+
UserProject: "UserProject",
|
|
36
|
+
Projects: "Projects",
|
|
37
|
+
ClientRoot: "ClientRoot",
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
/** Resource type name prefix constants. */
|
|
41
|
+
export const ResourceTypePrefix = {
|
|
42
|
+
Blob: "Blob/",
|
|
43
|
+
BlobUpload: "BlobUpload/",
|
|
44
|
+
BlobIndex: "BlobIndex/",
|
|
45
|
+
PColumnData: "PColumnData/",
|
|
46
|
+
StreamWorkdir: "StreamWorkdir/",
|
|
47
|
+
} as const;
|