@milaboratories/pf-spec 1.0.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/_virtual/_@oxc-project_runtime@0.137.0/helpers/esm/usingCtx.js +57 -0
- package/dist/axes.d.ts +9 -0
- package/dist/axes.d.ts.map +1 -0
- package/dist/axes.js +36 -0
- package/dist/axes.js.map +1 -0
- package/dist/build-query.d.ts +7 -0
- package/dist/build-query.d.ts.map +1 -0
- package/dist/build-query.js +9 -0
- package/dist/build-query.js.map +1 -0
- package/dist/generated/pframes_rs_wasip2.core.wasm +0 -0
- package/dist/generated/pframes_rs_wasip2.js +6389 -0
- package/dist/generated/pframes_rs_wasip2.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/p-frame.d.ts +48 -0
- package/dist/p-frame.d.ts.map +1 -0
- package/dist/p-frame.js +109 -0
- package/dist/p-frame.js.map +1 -0
- package/dist/rewrite-filters.d.ts +20 -0
- package/dist/rewrite-filters.d.ts.map +1 -0
- package/dist/rewrite-filters.js +19 -0
- package/dist/rewrite-filters.js.map +1 -0
- package/dist/table.d.ts +7 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +22 -0
- package/dist/table.js.map +1 -0
- package/package.json +50 -0
- package/src/axes.test.ts +24 -0
- package/src/axes.ts +20 -0
- package/src/build-query.ts +6 -0
- package/src/index.ts +44 -0
- package/src/p-frame.test.ts +265 -0
- package/src/p-frame.ts +148 -0
- package/src/rewrite-filters.ts +23 -0
- package/src/table.test.ts +35 -0
- package/src/table.ts +11 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { collapse, expand, find } from "./axes.js";
|
|
2
|
+
import { build } from "./build-query.js";
|
|
3
|
+
import { LegacyQuery, PFrame } from "./p-frame.js";
|
|
4
|
+
import { rewriteLegacyFilters as rewriteLegacyFilters$1 } from "./rewrite-filters.js";
|
|
5
|
+
import { findColumn } from "./table.js";
|
|
6
|
+
import { PColumnSpec } from "@milaboratories/pl-model-common";
|
|
7
|
+
|
|
8
|
+
//#region src/index.d.ts
|
|
9
|
+
/** Creates a {@link PFrame} from a map of column ids to column specifications. */
|
|
10
|
+
declare const createPFrame: (spec: Record<string, PColumnSpec>) => PFrame;
|
|
11
|
+
/** Expands an `AxesSpec` into `AxesId`s and resolves the parent information. */
|
|
12
|
+
declare const expandAxes: typeof expand;
|
|
13
|
+
/** This operation is the inverse of {@link expandAxes}. */
|
|
14
|
+
declare const collapseAxes: typeof collapse;
|
|
15
|
+
/** Returns the index of the axis that matches `selector`, or -1 if no axis matches. */
|
|
16
|
+
declare const findAxis: typeof find;
|
|
17
|
+
/**
|
|
18
|
+
* Returns the index of the table column that matches `selector`. It returns -1 if no
|
|
19
|
+
* column matches. A table spec indexes the axes first and then the columns.
|
|
20
|
+
*/
|
|
21
|
+
declare const findTableColumn: typeof findColumn;
|
|
22
|
+
/**
|
|
23
|
+
* Assembles a `SpecQueryJoinEntry` from a terminal column and an ordered path of
|
|
24
|
+
* steps. The steps are linker hops and filter joins.
|
|
25
|
+
*
|
|
26
|
+
* The operation is a right fold over `path`, and it starts at the column. Each
|
|
27
|
+
* `linker` step wraps the current subquery as a `linkerJoin`. Each `filter` step
|
|
28
|
+
* wraps the current subquery as an `innerJoin` with the filter column.
|
|
29
|
+
* `qualifications` annotate only the outermost entry.
|
|
30
|
+
*/
|
|
31
|
+
declare const buildQuery: typeof build;
|
|
32
|
+
/**
|
|
33
|
+
* Upgrades the selector-based legacy record filters into index-based boolean
|
|
34
|
+
* expressions for the data layer. It resolves them against the given unified table
|
|
35
|
+
* spec.
|
|
36
|
+
*/
|
|
37
|
+
declare const rewriteLegacyFilters: typeof rewriteLegacyFilters$1;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { type LegacyQuery, PFrame, buildQuery, collapseAxes, createPFrame, expandAxes, findAxis, findTableColumn, rewriteLegacyFilters };
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;cAUa,YAAA,GAAgB,IAAA,EAAM,MAAA,SAAe,WAAA,MAAe,MAAA;;cAGpD,UAAA,SAAU,MAAc;;cAGxB,YAAA,SAAY,QAAgB;;cAG5B,QAAA,SAAQ,IAAY;;;;;cAMpB,eAAA,SAAe,UAAmB;;AAf4C;AAG3F;;;;AAAqC;AAGrC;;cAoBa,UAAA,SAAU,KAAyB;;AApBP;AAGzC;;;cAwBa,oBAAA,SAAoB,sBAA4C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { collapse, expand, find } from "./axes.js";
|
|
2
|
+
import { build } from "./build-query.js";
|
|
3
|
+
import { PFrame } from "./p-frame.js";
|
|
4
|
+
import { rewriteLegacyFilters as rewriteLegacyFilters$1 } from "./rewrite-filters.js";
|
|
5
|
+
import { findColumn } from "./table.js";
|
|
6
|
+
//#region src/index.ts
|
|
7
|
+
/** Creates a {@link PFrame} from a map of column ids to column specifications. */
|
|
8
|
+
const createPFrame = (spec) => new PFrame(spec);
|
|
9
|
+
/** Expands an `AxesSpec` into `AxesId`s and resolves the parent information. */
|
|
10
|
+
const expandAxes = expand;
|
|
11
|
+
/** This operation is the inverse of {@link expandAxes}. */
|
|
12
|
+
const collapseAxes = collapse;
|
|
13
|
+
/** Returns the index of the axis that matches `selector`, or -1 if no axis matches. */
|
|
14
|
+
const findAxis = find;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the index of the table column that matches `selector`. It returns -1 if no
|
|
17
|
+
* column matches. A table spec indexes the axes first and then the columns.
|
|
18
|
+
*/
|
|
19
|
+
const findTableColumn = findColumn;
|
|
20
|
+
/**
|
|
21
|
+
* Assembles a `SpecQueryJoinEntry` from a terminal column and an ordered path of
|
|
22
|
+
* steps. The steps are linker hops and filter joins.
|
|
23
|
+
*
|
|
24
|
+
* The operation is a right fold over `path`, and it starts at the column. Each
|
|
25
|
+
* `linker` step wraps the current subquery as a `linkerJoin`. Each `filter` step
|
|
26
|
+
* wraps the current subquery as an `innerJoin` with the filter column.
|
|
27
|
+
* `qualifications` annotate only the outermost entry.
|
|
28
|
+
*/
|
|
29
|
+
const buildQuery = build;
|
|
30
|
+
/**
|
|
31
|
+
* Upgrades the selector-based legacy record filters into index-based boolean
|
|
32
|
+
* expressions for the data layer. It resolves them against the given unified table
|
|
33
|
+
* spec.
|
|
34
|
+
*/
|
|
35
|
+
const rewriteLegacyFilters = rewriteLegacyFilters$1;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { PFrame, buildQuery, collapseAxes, createPFrame, expandAxes, findAxis, findTableColumn, rewriteLegacyFilters };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["axes.expand","axes.collapse","axes.find","table.findColumn","buildQueryModule.build","rewriteFiltersModule.rewriteLegacyFilters"],"sources":["../src/index.ts"],"sourcesContent":["import type { PColumnSpec } from \"@milaboratories/pl-model-common\";\nimport * as axes from \"./axes.ts\";\nimport * as buildQueryModule from \"./build-query.ts\";\nimport { PFrame } from \"./p-frame.ts\";\nimport * as rewriteFiltersModule from \"./rewrite-filters.ts\";\nimport * as table from \"./table.ts\";\n\nexport { PFrame, type LegacyQuery } from \"./p-frame\";\n\n/** Creates a {@link PFrame} from a map of column ids to column specifications. */\nexport const createPFrame = (spec: Record<string, PColumnSpec>): PFrame => new PFrame(spec);\n\n/** Expands an `AxesSpec` into `AxesId`s and resolves the parent information. */\nexport const expandAxes = axes.expand;\n\n/** This operation is the inverse of {@link expandAxes}. */\nexport const collapseAxes = axes.collapse;\n\n/** Returns the index of the axis that matches `selector`, or -1 if no axis matches. */\nexport const findAxis = axes.find;\n\n/**\n * Returns the index of the table column that matches `selector`. It returns -1 if no\n * column matches. A table spec indexes the axes first and then the columns.\n */\nexport const findTableColumn = table.findColumn;\n\n/**\n * Assembles a `SpecQueryJoinEntry` from a terminal column and an ordered path of\n * steps. The steps are linker hops and filter joins.\n *\n * The operation is a right fold over `path`, and it starts at the column. Each\n * `linker` step wraps the current subquery as a `linkerJoin`. Each `filter` step\n * wraps the current subquery as an `innerJoin` with the filter column.\n * `qualifications` annotate only the outermost entry.\n */\nexport const buildQuery = buildQueryModule.build;\n\n/**\n * Upgrades the selector-based legacy record filters into index-based boolean\n * expressions for the data layer. It resolves them against the given unified table\n * spec.\n */\nexport const rewriteLegacyFilters = rewriteFiltersModule.rewriteLegacyFilters;\n"],"mappings":";;;;;;;AAUA,MAAa,gBAAgB,SAA8C,IAAI,OAAO,IAAI;;AAG1F,MAAa,aAAaA;;AAG1B,MAAa,eAAeC;;AAG5B,MAAa,WAAWC;;;;;AAMxB,MAAa,kBAAkBC;;;;;;;;;;AAW/B,MAAa,aAAaC;;;;;;AAO1B,MAAa,uBAAuBC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { EvaluateQueryResponse, JoinEntry, PColumnIdAndSpec, PColumnSpec, PObjectId, PTableRecordFilter, PTableSorting, SpecQuery } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
3
|
+
|
|
4
|
+
//#region src/p-frame.d.ts
|
|
5
|
+
/** A legacy (V4) query. Code used this type before the unified `SpecQuery`. */
|
|
6
|
+
type LegacyQuery = {
|
|
7
|
+
/** The source join entry. It defines the data sources and the join structure. */src: JoinEntry<PObjectId>; /** Optional record-level filters. The query applies these to its results. */
|
|
8
|
+
filters?: PTableRecordFilter[]; /** Optional sort specifications. They set the order of the results. */
|
|
9
|
+
sorting?: PTableSorting[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A set of registered column specs, and the spec-plane operations on them.
|
|
13
|
+
*
|
|
14
|
+
* Each method uses the specs that this frame holds. No method reads data. The module
|
|
15
|
+
* surface holds the spec operations that do not need a frame.
|
|
16
|
+
*
|
|
17
|
+
* This class holds a WASM resource. Use a `using` declaration to release it. Garbage
|
|
18
|
+
* collection also releases the resource, but not at a known time.
|
|
19
|
+
*/
|
|
20
|
+
declare class PFrame implements Disposable {
|
|
21
|
+
#private;
|
|
22
|
+
constructor(spec: Record<string, PColumnSpec>);
|
|
23
|
+
/** Deletes columns from a columns specification. */
|
|
24
|
+
deleteColumns(request: PFrameInternal.DeleteColumnFromColumnsRequest): PFrameInternal.DeleteColumnFromColumnsResponse;
|
|
25
|
+
/** Returns `null` if this frame has no column with the id `columnId`. */
|
|
26
|
+
getColumn(columnId: PObjectId): PColumnIdAndSpec | null;
|
|
27
|
+
/** Lists each column in this frame with its id and its spec. */
|
|
28
|
+
listColumns(): PColumnIdAndSpec[];
|
|
29
|
+
/**
|
|
30
|
+
* Discovers the columns that are compatible with a given axes integration.
|
|
31
|
+
*
|
|
32
|
+
* The include filters and the exclude filters apply in order. The exclude filters
|
|
33
|
+
* remove matches from the include set. Each hit has its own traversal `path`. To
|
|
34
|
+
* materialize a hit as a `SpecQueryJoinEntry`, give the hit's column id and `path`
|
|
35
|
+
* to {@link buildQuery}.
|
|
36
|
+
*/
|
|
37
|
+
discoverColumns(request: PFrameInternal.DiscoverColumnsRequestV2): PFrameInternal.DiscoverColumnsResponse;
|
|
38
|
+
/** Finds the columns in this frame that match the given filter criteria. */
|
|
39
|
+
findColumns(request: PFrameInternal.FindColumnsRequest): PFrameInternal.FindColumnsResponse;
|
|
40
|
+
/** Resolves a query against this frame's specs. Returns a table spec and a data query. */
|
|
41
|
+
evaluateQuery(request: SpecQuery): EvaluateQueryResponse;
|
|
42
|
+
/** Upgrades a {@link LegacyQuery} to the current `SpecQuery` format. */
|
|
43
|
+
rewriteLegacyQuery(request: LegacyQuery): SpecQuery;
|
|
44
|
+
[Symbol.dispose](): void;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { LegacyQuery, PFrame };
|
|
48
|
+
//# sourceMappingURL=p-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"p-frame.d.ts","names":[],"sources":["../src/p-frame.ts"],"mappings":";;;;;KAeY,WAAA;EAAA,iFAEV,GAAA,EAAK,SAAA,CAAU,SAAA;EAEf,OAAA,GAAU,kBAAA,IAFL;EAIL,OAAA,GAAU,aAAA;AAAA;;;;;;;;;;cAYC,MAAA,YAAkB,UAAA;EAAA;cAGjB,IAAA,EAAM,MAAA,SAAe,WAAA;EAHf;EAQlB,aAAA,CACE,OAAA,EAAS,cAAA,CAAe,8BAAA,GACvB,cAAA,CAAe,+BAAA;EAPe;EAYjC,SAAA,CAAU,QAAA,EAAU,SAAA,GAAY,gBAAA;EANrB;EAWX,WAAA,IAAe,gBAAA;EALK;;;;;;;;EAkBpB,eAAA,CACE,OAAA,EAAS,cAAA,CAAe,wBAAA,GACvB,cAAA,CAAe,uBAAA;EAeU;EAV5B,WAAA,CAAY,OAAA,EAAS,cAAA,CAAe,kBAAA,GAAqB,cAAA,CAAe,mBAAA;EAevE;EAVD,aAAA,CAAc,OAAA,EAAS,SAAA,GAAY,qBAAA;EA7CI;EAkDvC,kBAAA,CAAmB,OAAA,EAAS,WAAA,GAAc,SAAA;EAAA,CAKzC,MAAA,CAAO,OAAA;AAAA"}
|
package/dist/p-frame.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { spec } from "./generated/pframes_rs_wasip2.js";
|
|
2
|
+
//#region src/p-frame.ts
|
|
3
|
+
/**
|
|
4
|
+
* A set of registered column specs, and the spec-plane operations on them.
|
|
5
|
+
*
|
|
6
|
+
* Each method uses the specs that this frame holds. No method reads data. The module
|
|
7
|
+
* surface holds the spec operations that do not need a frame.
|
|
8
|
+
*
|
|
9
|
+
* This class holds a WASM resource. Use a `using` declaration to release it. Garbage
|
|
10
|
+
* collection also releases the resource, but not at a known time.
|
|
11
|
+
*/
|
|
12
|
+
var PFrame = class {
|
|
13
|
+
#frame;
|
|
14
|
+
constructor(spec$1) {
|
|
15
|
+
this.#frame = spec.Frame.fromJson(JSON.stringify(spec$1));
|
|
16
|
+
}
|
|
17
|
+
/** Deletes columns from a columns specification. */
|
|
18
|
+
deleteColumns(request) {
|
|
19
|
+
return JSON.parse(spec.Frame.deleteColumns(JSON.stringify(request)));
|
|
20
|
+
}
|
|
21
|
+
/** Returns `null` if this frame has no column with the id `columnId`. */
|
|
22
|
+
getColumn(columnId) {
|
|
23
|
+
return JSON.parse(this.#frame.getColumn(JSON.stringify(columnId)));
|
|
24
|
+
}
|
|
25
|
+
/** Lists each column in this frame with its id and its spec. */
|
|
26
|
+
listColumns() {
|
|
27
|
+
const columns = JSON.parse(this.#frame.listColumns());
|
|
28
|
+
return Object.values(columns);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Discovers the columns that are compatible with a given axes integration.
|
|
32
|
+
*
|
|
33
|
+
* The include filters and the exclude filters apply in order. The exclude filters
|
|
34
|
+
* remove matches from the include set. Each hit has its own traversal `path`. To
|
|
35
|
+
* materialize a hit as a `SpecQueryJoinEntry`, give the hit's column id and `path`
|
|
36
|
+
* to {@link buildQuery}.
|
|
37
|
+
*/
|
|
38
|
+
discoverColumns(request) {
|
|
39
|
+
return JSON.parse(this.#frame.discoverColumns(JSON.stringify(request)));
|
|
40
|
+
}
|
|
41
|
+
/** Finds the columns in this frame that match the given filter criteria. */
|
|
42
|
+
findColumns(request) {
|
|
43
|
+
return JSON.parse(this.#frame.findColumns(JSON.stringify(request)));
|
|
44
|
+
}
|
|
45
|
+
/** Resolves a query against this frame's specs. Returns a table spec and a data query. */
|
|
46
|
+
evaluateQuery(request) {
|
|
47
|
+
return JSON.parse(this.#frame.evaluateQuery(JSON.stringify(request)));
|
|
48
|
+
}
|
|
49
|
+
/** Upgrades a {@link LegacyQuery} to the current `SpecQuery` format. */
|
|
50
|
+
rewriteLegacyQuery(request) {
|
|
51
|
+
const src = joinEntryToInternal(request.src);
|
|
52
|
+
return JSON.parse(this.#frame.rewriteLegacyQuery(JSON.stringify({
|
|
53
|
+
...request,
|
|
54
|
+
src
|
|
55
|
+
})));
|
|
56
|
+
}
|
|
57
|
+
[Symbol.dispose]() {
|
|
58
|
+
this.#frame[Symbol.dispose]();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function joinEntryToInternal(entry) {
|
|
62
|
+
const type = entry.type;
|
|
63
|
+
switch (type) {
|
|
64
|
+
case "column": return {
|
|
65
|
+
type: "column",
|
|
66
|
+
columnId: entry.column
|
|
67
|
+
};
|
|
68
|
+
case "slicedColumn": return {
|
|
69
|
+
type: "slicedColumn",
|
|
70
|
+
columnId: entry.column,
|
|
71
|
+
newId: entry.newId,
|
|
72
|
+
axisFilters: entry.axisFilters
|
|
73
|
+
};
|
|
74
|
+
case "artificialColumn": return {
|
|
75
|
+
type: "artificialColumn",
|
|
76
|
+
columnId: entry.column,
|
|
77
|
+
newId: entry.newId,
|
|
78
|
+
axesIndices: entry.axesIndices
|
|
79
|
+
};
|
|
80
|
+
case "inlineColumn": return {
|
|
81
|
+
type: "inlineColumn",
|
|
82
|
+
newId: entry.column.id,
|
|
83
|
+
spec: entry.column.spec,
|
|
84
|
+
dataInfo: {
|
|
85
|
+
type: "Json",
|
|
86
|
+
keyLength: entry.column.spec.axesSpec.length,
|
|
87
|
+
data: entry.column.data.reduce((acc, row) => {
|
|
88
|
+
acc[JSON.stringify(row.key)] = row.val;
|
|
89
|
+
return acc;
|
|
90
|
+
}, {})
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
case "inner":
|
|
94
|
+
case "full": return {
|
|
95
|
+
type: entry.type,
|
|
96
|
+
entries: entry.entries.map((col) => joinEntryToInternal(col))
|
|
97
|
+
};
|
|
98
|
+
case "outer": return {
|
|
99
|
+
type: "outer",
|
|
100
|
+
primary: joinEntryToInternal(entry.primary),
|
|
101
|
+
secondary: entry.secondary.map((col) => joinEntryToInternal(col))
|
|
102
|
+
};
|
|
103
|
+
default: throw new Error(`unsupported PFrame join entry type: ${type}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { PFrame };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=p-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"p-frame.js","names":["#frame","bindings","spec"],"sources":["../src/p-frame.ts"],"sourcesContent":["import type {\n EvaluateQueryResponse,\n JoinEntry,\n PColumnIdAndSpec,\n PColumnSpec,\n PColumnValue,\n PObjectId,\n PTableRecordFilter,\n PTableSorting,\n SpecQuery,\n} from \"@milaboratories/pl-model-common\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { spec as bindings } from \"./generated/pframes_rs_wasip2.js\";\n\n/** A legacy (V4) query. Code used this type before the unified `SpecQuery`. */\nexport type LegacyQuery = {\n /** The source join entry. It defines the data sources and the join structure. */\n src: JoinEntry<PObjectId>;\n /** Optional record-level filters. The query applies these to its results. */\n filters?: PTableRecordFilter[];\n /** Optional sort specifications. They set the order of the results. */\n sorting?: PTableSorting[];\n};\n\n/**\n * A set of registered column specs, and the spec-plane operations on them.\n *\n * Each method uses the specs that this frame holds. No method reads data. The module\n * surface holds the spec operations that do not need a frame.\n *\n * This class holds a WASM resource. Use a `using` declaration to release it. Garbage\n * collection also releases the resource, but not at a known time.\n */\nexport class PFrame implements Disposable {\n #frame: bindings.Frame;\n\n constructor(spec: Record<string, PColumnSpec>) {\n this.#frame = bindings.Frame.fromJson(JSON.stringify(spec));\n }\n\n /** Deletes columns from a columns specification. */\n deleteColumns(\n request: PFrameInternal.DeleteColumnFromColumnsRequest,\n ): PFrameInternal.DeleteColumnFromColumnsResponse {\n return JSON.parse(bindings.Frame.deleteColumns(JSON.stringify(request)));\n }\n\n /** Returns `null` if this frame has no column with the id `columnId`. */\n getColumn(columnId: PObjectId): PColumnIdAndSpec | null {\n return JSON.parse(this.#frame.getColumn(JSON.stringify(columnId)));\n }\n\n /** Lists each column in this frame with its id and its spec. */\n listColumns(): PColumnIdAndSpec[] {\n const columns = JSON.parse(this.#frame.listColumns()) as Record<string, PColumnIdAndSpec>;\n return Object.values(columns);\n }\n\n /**\n * Discovers the columns that are compatible with a given axes integration.\n *\n * The include filters and the exclude filters apply in order. The exclude filters\n * remove matches from the include set. Each hit has its own traversal `path`. To\n * materialize a hit as a `SpecQueryJoinEntry`, give the hit's column id and `path`\n * to {@link buildQuery}.\n */\n discoverColumns(\n request: PFrameInternal.DiscoverColumnsRequestV2,\n ): PFrameInternal.DiscoverColumnsResponse {\n return JSON.parse(this.#frame.discoverColumns(JSON.stringify(request)));\n }\n\n /** Finds the columns in this frame that match the given filter criteria. */\n findColumns(request: PFrameInternal.FindColumnsRequest): PFrameInternal.FindColumnsResponse {\n return JSON.parse(this.#frame.findColumns(JSON.stringify(request)));\n }\n\n /** Resolves a query against this frame's specs. Returns a table spec and a data query. */\n evaluateQuery(request: SpecQuery): EvaluateQueryResponse {\n return JSON.parse(this.#frame.evaluateQuery(JSON.stringify(request)));\n }\n\n /** Upgrades a {@link LegacyQuery} to the current `SpecQuery` format. */\n rewriteLegacyQuery(request: LegacyQuery): SpecQuery {\n const src = joinEntryToInternal(request.src);\n return JSON.parse(this.#frame.rewriteLegacyQuery(JSON.stringify({ ...request, src })));\n }\n\n [Symbol.dispose](): void {\n this.#frame[Symbol.dispose]();\n }\n}\n\nfunction joinEntryToInternal(entry: JoinEntry<PObjectId>): PFrameInternal.JoinEntryV4 {\n const type = entry.type;\n switch (type) {\n case \"column\":\n return {\n type: \"column\",\n columnId: entry.column,\n };\n case \"slicedColumn\":\n return {\n type: \"slicedColumn\",\n columnId: entry.column,\n newId: entry.newId,\n axisFilters: entry.axisFilters,\n };\n case \"artificialColumn\":\n return {\n type: \"artificialColumn\",\n columnId: entry.column,\n newId: entry.newId,\n axesIndices: entry.axesIndices,\n };\n case \"inlineColumn\":\n return {\n type: \"inlineColumn\",\n newId: entry.column.id,\n spec: entry.column.spec,\n dataInfo: {\n type: \"Json\",\n keyLength: entry.column.spec.axesSpec.length,\n data: entry.column.data.reduce(\n (acc, row) => {\n acc[JSON.stringify(row.key)] = row.val;\n return acc;\n },\n {} as Record<string, PColumnValue>,\n ),\n },\n };\n case \"inner\":\n case \"full\":\n return {\n type: entry.type,\n entries: entry.entries.map((col) => joinEntryToInternal(col)),\n };\n case \"outer\":\n return {\n type: \"outer\",\n primary: joinEntryToInternal(entry.primary),\n secondary: entry.secondary.map((col) => joinEntryToInternal(col)),\n };\n default:\n throw new Error(`unsupported PFrame join entry type: ${type satisfies never}`);\n }\n}\n"],"mappings":";;;;;;;;;;;AAiCA,IAAa,SAAb,MAA0C;CACxC;CAEA,YAAY,QAAmC;EAC7C,KAAKA,SAASC,KAAS,MAAM,SAAS,KAAK,UAAUC,MAAI,CAAC;CAC5D;;CAGA,cACE,SACgD;EAChD,OAAO,KAAK,MAAMD,KAAS,MAAM,cAAc,KAAK,UAAU,OAAO,CAAC,CAAC;CACzE;;CAGA,UAAU,UAA8C;EACtD,OAAO,KAAK,MAAM,KAAKD,OAAO,UAAU,KAAK,UAAU,QAAQ,CAAC,CAAC;CACnE;;CAGA,cAAkC;EAChC,MAAM,UAAU,KAAK,MAAM,KAAKA,OAAO,YAAY,CAAC;EACpD,OAAO,OAAO,OAAO,OAAO;CAC9B;;;;;;;;;CAUA,gBACE,SACwC;EACxC,OAAO,KAAK,MAAM,KAAKA,OAAO,gBAAgB,KAAK,UAAU,OAAO,CAAC,CAAC;CACxE;;CAGA,YAAY,SAAgF;EAC1F,OAAO,KAAK,MAAM,KAAKA,OAAO,YAAY,KAAK,UAAU,OAAO,CAAC,CAAC;CACpE;;CAGA,cAAc,SAA2C;EACvD,OAAO,KAAK,MAAM,KAAKA,OAAO,cAAc,KAAK,UAAU,OAAO,CAAC,CAAC;CACtE;;CAGA,mBAAmB,SAAiC;EAClD,MAAM,MAAM,oBAAoB,QAAQ,GAAG;EAC3C,OAAO,KAAK,MAAM,KAAKA,OAAO,mBAAmB,KAAK,UAAU;GAAE,GAAG;GAAS;EAAI,CAAC,CAAC,CAAC;CACvF;CAEA,CAAC,OAAO,WAAiB;EACvB,KAAKA,OAAO,OAAO,QAAQ,CAAC;CAC9B;AACF;AAEA,SAAS,oBAAoB,OAAyD;CACpF,MAAM,OAAO,MAAM;CACnB,QAAQ,MAAR;EACE,KAAK,UACH,OAAO;GACL,MAAM;GACN,UAAU,MAAM;EAClB;EACF,KAAK,gBACH,OAAO;GACL,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;GACb,aAAa,MAAM;EACrB;EACF,KAAK,oBACH,OAAO;GACL,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;GACb,aAAa,MAAM;EACrB;EACF,KAAK,gBACH,OAAO;GACL,MAAM;GACN,OAAO,MAAM,OAAO;GACpB,MAAM,MAAM,OAAO;GACnB,UAAU;IACR,MAAM;IACN,WAAW,MAAM,OAAO,KAAK,SAAS;IACtC,MAAM,MAAM,OAAO,KAAK,QACrB,KAAK,QAAQ;KACZ,IAAI,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI;KACnC,OAAO;IACT,GACA,CAAC,CACH;GACF;EACF;EACF,KAAK;EACL,KAAK,QACH,OAAO;GACL,MAAM,MAAM;GACZ,SAAS,MAAM,QAAQ,KAAK,QAAQ,oBAAoB,GAAG,CAAC;EAC9D;EACF,KAAK,SACH,OAAO;GACL,MAAM;GACN,SAAS,oBAAoB,MAAM,OAAO;GAC1C,WAAW,MAAM,UAAU,KAAK,QAAQ,oBAAoB,GAAG,CAAC;EAClE;EACF,SACE,MAAM,IAAI,MAAM,uCAAuC,MAAsB;CACjF;AACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DataQueryBooleanExpression, PTableColumnSpec, PTableRecordFilter } from "@milaboratories/pl-model-common";
|
|
2
|
+
|
|
3
|
+
//#region src/rewrite-filters.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Upgrades the selector-based legacy record filters into index-based boolean
|
|
6
|
+
* expressions for the data layer. It resolves them against the given unified
|
|
7
|
+
* table spec, which holds the axes first and then the columns.
|
|
8
|
+
*
|
|
9
|
+
* The operation is stateless, because a filter does not change the spec of a
|
|
10
|
+
* table. Therefore the result is valid for `getUniqueValues`, which works on
|
|
11
|
+
* the single-column table of the source column. The result is also valid when
|
|
12
|
+
* you compose a `filter` over a `table` query node.
|
|
13
|
+
*/
|
|
14
|
+
declare function rewriteLegacyFilters(request: {
|
|
15
|
+
tableSpec: PTableColumnSpec[];
|
|
16
|
+
filters: PTableRecordFilter[];
|
|
17
|
+
}): DataQueryBooleanExpression[];
|
|
18
|
+
//#endregion
|
|
19
|
+
export { rewriteLegacyFilters };
|
|
20
|
+
//# sourceMappingURL=rewrite-filters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite-filters.d.ts","names":[],"sources":["../src/rewrite-filters.ts"],"mappings":";;;;;AAiBA;;;;;;;;iBAAgB,oBAAA,CAAqB,OAAA;EACnC,SAAA,EAAW,gBAAA;EACX,OAAA,EAAS,kBAAA;AAAA,IACP,0BAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { spec } from "./generated/pframes_rs_wasip2.js";
|
|
2
|
+
//#region src/rewrite-filters.ts
|
|
3
|
+
/**
|
|
4
|
+
* Upgrades the selector-based legacy record filters into index-based boolean
|
|
5
|
+
* expressions for the data layer. It resolves them against the given unified
|
|
6
|
+
* table spec, which holds the axes first and then the columns.
|
|
7
|
+
*
|
|
8
|
+
* The operation is stateless, because a filter does not change the spec of a
|
|
9
|
+
* table. Therefore the result is valid for `getUniqueValues`, which works on
|
|
10
|
+
* the single-column table of the source column. The result is also valid when
|
|
11
|
+
* you compose a `filter` over a `table` query node.
|
|
12
|
+
*/
|
|
13
|
+
function rewriteLegacyFilters(request) {
|
|
14
|
+
return JSON.parse(spec.Frame.rewriteLegacyFilters(JSON.stringify(request)));
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { rewriteLegacyFilters };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=rewrite-filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite-filters.js","names":["bindings"],"sources":["../src/rewrite-filters.ts"],"sourcesContent":["import type {\n DataQueryBooleanExpression,\n PTableColumnSpec,\n PTableRecordFilter,\n} from \"@milaboratories/pl-model-common\";\nimport { spec as bindings } from \"./generated/pframes_rs_wasip2.js\";\n\n/**\n * Upgrades the selector-based legacy record filters into index-based boolean\n * expressions for the data layer. It resolves them against the given unified\n * table spec, which holds the axes first and then the columns.\n *\n * The operation is stateless, because a filter does not change the spec of a\n * table. Therefore the result is valid for `getUniqueValues`, which works on\n * the single-column table of the source column. The result is also valid when\n * you compose a `filter` over a `table` query node.\n */\nexport function rewriteLegacyFilters(request: {\n tableSpec: PTableColumnSpec[];\n filters: PTableRecordFilter[];\n}): DataQueryBooleanExpression[] {\n return JSON.parse(bindings.Frame.rewriteLegacyFilters(JSON.stringify(request)));\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,SAAgB,qBAAqB,SAGJ;CAC/B,OAAO,KAAK,MAAMA,KAAS,MAAM,qBAAqB,KAAK,UAAU,OAAO,CAAC,CAAC;AAChF"}
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PTableColumnId, PTableColumnSpec } from "@milaboratories/pl-model-common";
|
|
2
|
+
|
|
3
|
+
//#region src/table.d.ts
|
|
4
|
+
declare function findColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { findColumn };
|
|
7
|
+
//# sourceMappingURL=table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","names":[],"sources":["../src/table.ts"],"mappings":";;;iBAGgB,UAAA,CAAW,SAAA,EAAW,gBAAA,IAAoB,QAAA,EAAU,cAAc"}
|
package/dist/table.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { spec } from "./generated/pframes_rs_wasip2.js";
|
|
2
|
+
import _usingCtx from "./_virtual/_@oxc-project_runtime@0.137.0/helpers/esm/usingCtx.js";
|
|
3
|
+
//#region src/table.ts
|
|
4
|
+
function findColumn(tableSpec, selector) {
|
|
5
|
+
try {
|
|
6
|
+
var _usingCtx$1 = _usingCtx();
|
|
7
|
+
const table = _usingCtx$1.u(spec.Table.fromJson(JSON.stringify(tableSpec)));
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(table.findColumn(JSON.stringify(selector)));
|
|
10
|
+
} catch {
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
} catch (_) {
|
|
14
|
+
_usingCtx$1.e = _;
|
|
15
|
+
} finally {
|
|
16
|
+
_usingCtx$1.d();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { findColumn };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","names":["bindings"],"sources":["../src/table.ts"],"sourcesContent":["import type { PTableColumnId, PTableColumnSpec } from \"@milaboratories/pl-model-common\";\nimport { spec as bindings } from \"./generated/pframes_rs_wasip2.js\";\n\nexport function findColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number {\n using table = bindings.Table.fromJson(JSON.stringify(tableSpec));\n try {\n return JSON.parse(table.findColumn(JSON.stringify(selector)));\n } catch {\n return -1;\n }\n}\n"],"mappings":";;;AAGA,SAAgB,WAAW,WAA+B,UAAkC;;;EAC1F,MAAM,QAAA,YAAA,EAAQA,KAAS,MAAM,SAAS,KAAK,UAAU,SAAS,CAAC,CAAA;EAC/D,IAAI;GACF,OAAO,KAAK,MAAM,MAAM,WAAW,KAAK,UAAU,QAAQ,CAAC,CAAC;EAC9D,QAAQ;GACN,OAAO;EACT;;;;;;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@milaboratories/pf-spec",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Spec-plane PFrame operations: bindings to the pframes WASM component",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"files": [
|
|
8
|
+
"./dist/**/*",
|
|
9
|
+
"./src/*.ts"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@milaboratories/pl-model-common": "1.47.3",
|
|
20
|
+
"@milaboratories/pl-model-middle-layer": "1.31.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@bytecodealliance/jco-transpile": "^0.6.3",
|
|
24
|
+
"@bytecodealliance/preview2-shim": "^0.20.1",
|
|
25
|
+
"@milaboratories/pframes-rs-wasip2": "1.1.56",
|
|
26
|
+
"@types/node": "~24.5.2",
|
|
27
|
+
"@vitest/coverage-istanbul": "^4.1.3",
|
|
28
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
29
|
+
"typescript": "~5.9.3",
|
|
30
|
+
"vitest": "^4.1.3",
|
|
31
|
+
"@milaboratories/build-configs": "2.0.0",
|
|
32
|
+
"@milaboratories/ts-configs": "1.4.0",
|
|
33
|
+
"@milaboratories/ts-builder": "1.6.2"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@bytecodealliance/preview2-shim": "^0.20.1"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"transpile": "node --conditions=wasm scripts/transpile.ts",
|
|
40
|
+
"build": "ts-builder build --target node --build-config build.config.js",
|
|
41
|
+
"watch": "ts-builder build --target node --build-config build.config.js --watch",
|
|
42
|
+
"check": "ts-builder check --target node",
|
|
43
|
+
"formatter:check": "ts-builder formatter --check",
|
|
44
|
+
"linter:check": "ts-builder linter --check",
|
|
45
|
+
"types:check": "ts-builder type-check --target node",
|
|
46
|
+
"test": "vitest run --coverage",
|
|
47
|
+
"do-pack": "rm -f *.tgz && pnpm pack && mv *.tgz package.tgz",
|
|
48
|
+
"fmt": "ts-builder format"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/axes.test.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { collapse, expand, find } from "./axes.ts";
|
|
3
|
+
|
|
4
|
+
const axesSpec = [{ type: "Int" as const, name: "a1" }];
|
|
5
|
+
|
|
6
|
+
test("expand", () => {
|
|
7
|
+
const ids = expand(axesSpec);
|
|
8
|
+
expect(ids).toEqual([{ name: "a1", type: "Int" }]);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("collapse", () => {
|
|
12
|
+
const spec = collapse([{ name: "a1", type: "Int" }]);
|
|
13
|
+
expect(spec).toEqual(axesSpec);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("find - match", () => {
|
|
17
|
+
const index = find(axesSpec, { name: "a1" });
|
|
18
|
+
expect(index).toBe(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("find - no match", () => {
|
|
22
|
+
const index = find(axesSpec, { name: "nonexistent" });
|
|
23
|
+
expect(index).toBe(-1);
|
|
24
|
+
});
|
package/src/axes.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AxesId, AxesSpec, SingleAxisSelector } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { spec as bindings } from "./generated/pframes_rs_wasip2.js";
|
|
3
|
+
|
|
4
|
+
export function expand(spec: AxesSpec): AxesId {
|
|
5
|
+
using axes = bindings.Axes.fromJson(JSON.stringify(spec));
|
|
6
|
+
return JSON.parse(axes.expand());
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function collapse(ids: AxesId): AxesSpec {
|
|
10
|
+
return JSON.parse(bindings.Axes.collapse(JSON.stringify(ids)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function find(spec: AxesSpec, selector: SingleAxisSelector): number {
|
|
14
|
+
using axes = bindings.Axes.fromJson(JSON.stringify(spec));
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(axes.find(JSON.stringify(selector)));
|
|
17
|
+
} catch {
|
|
18
|
+
return -1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BuildQueryInput, SpecQueryJoinEntry } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { spec as bindings } from "./generated/pframes_rs_wasip2.js";
|
|
3
|
+
|
|
4
|
+
export function build(input: BuildQueryInput): SpecQueryJoinEntry {
|
|
5
|
+
return JSON.parse(bindings.Frame.buildQuery(JSON.stringify(input)));
|
|
6
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PColumnSpec } from "@milaboratories/pl-model-common";
|
|
2
|
+
import * as axes from "./axes.ts";
|
|
3
|
+
import * as buildQueryModule from "./build-query.ts";
|
|
4
|
+
import { PFrame } from "./p-frame.ts";
|
|
5
|
+
import * as rewriteFiltersModule from "./rewrite-filters.ts";
|
|
6
|
+
import * as table from "./table.ts";
|
|
7
|
+
|
|
8
|
+
export { PFrame, type LegacyQuery } from "./p-frame";
|
|
9
|
+
|
|
10
|
+
/** Creates a {@link PFrame} from a map of column ids to column specifications. */
|
|
11
|
+
export const createPFrame = (spec: Record<string, PColumnSpec>): PFrame => new PFrame(spec);
|
|
12
|
+
|
|
13
|
+
/** Expands an `AxesSpec` into `AxesId`s and resolves the parent information. */
|
|
14
|
+
export const expandAxes = axes.expand;
|
|
15
|
+
|
|
16
|
+
/** This operation is the inverse of {@link expandAxes}. */
|
|
17
|
+
export const collapseAxes = axes.collapse;
|
|
18
|
+
|
|
19
|
+
/** Returns the index of the axis that matches `selector`, or -1 if no axis matches. */
|
|
20
|
+
export const findAxis = axes.find;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the index of the table column that matches `selector`. It returns -1 if no
|
|
24
|
+
* column matches. A table spec indexes the axes first and then the columns.
|
|
25
|
+
*/
|
|
26
|
+
export const findTableColumn = table.findColumn;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Assembles a `SpecQueryJoinEntry` from a terminal column and an ordered path of
|
|
30
|
+
* steps. The steps are linker hops and filter joins.
|
|
31
|
+
*
|
|
32
|
+
* The operation is a right fold over `path`, and it starts at the column. Each
|
|
33
|
+
* `linker` step wraps the current subquery as a `linkerJoin`. Each `filter` step
|
|
34
|
+
* wraps the current subquery as an `innerJoin` with the filter column.
|
|
35
|
+
* `qualifications` annotate only the outermost entry.
|
|
36
|
+
*/
|
|
37
|
+
export const buildQuery = buildQueryModule.build;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Upgrades the selector-based legacy record filters into index-based boolean
|
|
41
|
+
* expressions for the data layer. It resolves them against the given unified table
|
|
42
|
+
* spec.
|
|
43
|
+
*/
|
|
44
|
+
export const rewriteLegacyFilters = rewriteFiltersModule.rewriteLegacyFilters;
|