@milaboratories/pl-middle-layer 1.65.9 → 1.66.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/js_render/column_registry.cjs +56 -0
- package/dist/js_render/column_registry.cjs.map +1 -0
- package/dist/js_render/column_registry.js +55 -0
- package/dist/js_render/column_registry.js.map +1 -0
- package/dist/js_render/computable_context.cjs +80 -12
- package/dist/js_render/computable_context.cjs.map +1 -1
- package/dist/js_render/computable_context.js +81 -13
- package/dist/js_render/computable_context.js.map +1 -1
- package/dist/js_render/service_injectors.cjs +43 -2
- package/dist/js_render/service_injectors.cjs.map +1 -1
- package/dist/js_render/service_injectors.js +43 -2
- package/dist/js_render/service_injectors.js.map +1 -1
- package/dist/js_render/spec_override_collapse.cjs +108 -0
- package/dist/js_render/spec_override_collapse.cjs.map +1 -0
- package/dist/js_render/spec_override_collapse.js +108 -0
- package/dist/js_render/spec_override_collapse.js.map +1 -0
- package/dist/middle_layer/block_ctx.cjs +2 -1
- package/dist/middle_layer/block_ctx.cjs.map +1 -1
- package/dist/middle_layer/block_ctx.js +2 -1
- package/dist/middle_layer/block_ctx.js.map +1 -1
- package/dist/mutator/template/template_cache.cjs.map +1 -1
- package/dist/mutator/template/template_cache.d.ts.map +1 -1
- package/dist/mutator/template/template_cache.js.map +1 -1
- package/dist/pool/data.cjs +2 -9
- package/dist/pool/data.cjs.map +1 -1
- package/dist/pool/data.d.ts.map +1 -1
- package/dist/pool/data.js +3 -10
- package/dist/pool/data.js.map +1 -1
- package/dist/pool/result_pool.cjs +0 -20
- package/dist/pool/result_pool.cjs.map +1 -1
- package/dist/pool/result_pool.js +1 -21
- package/dist/pool/result_pool.js.map +1 -1
- package/dist/pool/upstream_block_ctx.cjs +64 -0
- package/dist/pool/upstream_block_ctx.cjs.map +1 -0
- package/dist/pool/upstream_block_ctx.js +64 -0
- package/dist/pool/upstream_block_ctx.js.map +1 -0
- package/dist/service_factories.cjs +3 -1
- package/dist/service_factories.cjs.map +1 -1
- package/dist/service_factories.js +3 -1
- package/dist/service_factories.js.map +1 -1
- package/package.json +18 -17
- package/src/js_render/column_registry.ts +95 -0
- package/src/js_render/computable_context.ts +109 -26
- package/src/js_render/service_injectors.ts +106 -8
- package/src/js_render/spec_override_collapse.ts +211 -0
- package/src/middle_layer/block_ctx.ts +6 -1
- package/src/mutator/template/template_cache.test.ts +0 -14
- package/src/mutator/template/template_cache.ts +0 -14
- package/src/pool/data.ts +4 -3
- package/src/pool/result_pool.ts +1 -24
- package/src/pool/upstream_block_ctx.ts +85 -0
- package/src/service_factories.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service_injectors.js","names":[],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n PTableRecordFilter,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n\n rewriteLegacyFilters: (request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.rewriteLegacyFilters(\n vm.importObjectViaJson(request) as {\n tableSpec: PTableColumnSpec[];\n filters: PTableRecordFilter[];\n },\n ),\n ),\n };\n },\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;AAkDA,SAAgB,sBAA0C;CACxD,OAAO;EACL,aAAa,EAAE,MAAM,SAAiC;GACpD,MAAM,SAAS,KAAK,gBAAgB,IAAI,SAAS,UAAU;GAC3D,IAAI,CAAC,QACH,MAAM,IAAI,0BACR,YAAY,SAAS,WAAW,sEAClC;GAEF,OAAO;IACL,kBAAkB,UAAyB;;;MACzC,MAAM,QAAA,YAAA,EAAQ,IAAI,eAChB,OAAO,gBAAgB,GAAG,oBAAoB,KAAK,CAAgC,CACrF,CAAA;MACA,KAAK,aAAa,MAAM,MAAM,KAAK;MACnC,MAAM,QAAQ,MAAM,KAAK;MAEzB,MAAM,MAAM,GAAG,GAAG,UAAU;MAC5B,GAAG,GAAG,UAAU,MAAM,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC;MACtE,GAAG,GACA,YAAY,eAAe;OAC1B,MAAM,MAAM;MACd,CAAC,CAAC,CACD,SAAS,OAAO,GAAG,GAAG,QAAQ,KAAK,SAAS,EAAE,CAAC;MAClD,OAAO;;;;;;IACT;IAEA,cAAc,WACZ,GAAG,oBAAoB,OAAO,YAAY,GAAG,GAAG,UAAU,MAAM,CAAoB,CAAC;IAEvF,kBAAkB,QAAuB,YACvC,GAAG,oBACD,OAAO,gBACL,GAAG,GAAG,UAAU,MAAM,GACtB,GAAG,oBAAoB,OAAO,CAChC,CACF;IAEF,aAAa,UACX,GAAG,oBACD,OAAO,WAAW,GAAG,oBAAoB,KAAK,CAAoB,CACpE;IAEF,eAAe,QAAuB,YACpC,GAAG,oBACD,OAAO,aACL,GAAG,GAAG,UAAU,MAAM,GACtB,GAAG,oBAAoB,OAAO,CAChC,CACF;IAEF,gBAAgB,QAAuB,YACrC,GAAG,oBACD,OAAO,cACL,GAAG,GAAG,UAAU,MAAM,GACtB,GAAG,oBAAoB,OAAO,CAChC,CACF;IAEF,aAAa,SACX,GAAG,oBAAoB,OAAO,WAAW,GAAG,oBAAoB,IAAI,CAAa,CAAC;IAEpF,eAAe,QACb,GAAG,oBAAoB,OAAO,aAAa,GAAG,oBAAoB,GAAG,CAAW,CAAC;IAEnF,WAAW,MAAqB,aAC9B,GAAG,kBACD,OAAO,SACL,GAAG,oBAAoB,IAAI,GAC3B,GAAG,oBAAoB,QAAQ,CACjC,CACF;IAEF,kBAAkB,WAA0B,aAC1C,GAAG,kBACD,OAAO,gBACL,GAAG,oBAAoB,SAAS,GAChC,GAAG,oBAAoB,QAAQ,CACjC,CACF;IAEF,uBAAuB,YACrB,GAAG,oBACD,OAAO,qBACL,GAAG,oBAAoB,OAAO,CAIhC,CACF;GACJ;EACF;EAIA,eAAe,CAAC;EAEhB,SAAS,EAAE,MAAM,UAAkC;GACjD,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,GAAG,CAG5B,CACF;GAEF,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,GAAG,CAG5B,CACF;GAEF,iBAAiB,QACf,GAAG,kBACD,KAAK,eACH,GAAG,oBAAoB,GAAG,CAG5B,CACF;EACJ;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"service_injectors.js","names":[],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type {\n CollectionHandle,\n ColumnsCollectionDriverHost,\n DiscoverColumnsOptions,\n InferServiceModel,\n PoolEntry,\n SerializedColumnsSource,\n ServiceBrand,\n} from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type { PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PObjectId,\n PTableColumnId,\n PTableColumnSpec,\n PTableRecordFilter,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n\n rewriteLegacyFilters: (request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.rewriteLegacyFilters(\n vm.importObjectViaJson(request) as {\n tableSpec: PTableColumnSpec[];\n filters: PTableRecordFilter[];\n },\n ),\n ),\n };\n },\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PObjectId | PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PObjectId | PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PObjectId | PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n ColumnsCollection: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.ColumnsCollection);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.ColumnsCollection}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n const specDriver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!specDriver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n const bindings: ColumnsCollectionDriverHost<PlTreeNodeAccessor> = {\n resolveAccessor: (h) => host.getAccessor(h),\n getUpstreamBlockCtxes: () => host.getRawUpstreamBlockCtx(),\n getSpecDriver: () => specDriver,\n resolveSpec: (id: PObjectId) => {\n const leaf = host.getColumnRegistry().resolve(id);\n if (leaf === undefined) return undefined;\n const specNode = leaf.accessor.traverse({\n field: `${leaf.name}.spec`,\n assertFieldType: \"Input\",\n ignoreError: true,\n });\n return specNode?.getDataAsJson<PColumnSpec>();\n },\n };\n\n const pinHandle = (entry: PoolEntry<CollectionHandle>): CollectionHandle => {\n using guard = new PoolEntryGuard(entry);\n host.addOnDestroy(guard.entry.unref);\n return guard.keep().key;\n };\n\n return {\n create: (sources: QuickJSHandle) =>\n vm.exportSingleValue(\n pinHandle(\n driver.create(vm.importObjectViaJson(sources) as SerializedColumnsSource[], bindings),\n ),\n ),\n\n isEmpty: (handle: QuickJSHandle) =>\n vm.exportSingleValue(driver.isEmpty(vm.vm.getString(handle) as CollectionHandle)),\n\n isFinal: (handle: QuickJSHandle) =>\n vm.exportSingleValue(driver.isFinal(vm.vm.getString(handle) as CollectionHandle)),\n\n getColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.getColumns(vm.vm.getString(handle) as CollectionHandle, bindings),\n ),\n\n addSource: (handle: QuickJSHandle, sources: QuickJSHandle) =>\n vm.exportSingleValue(\n pinHandle(\n driver.addSource(\n vm.vm.getString(handle) as CollectionHandle,\n vm.importObjectViaJson(sources) as SerializedColumnsSource[],\n bindings,\n ),\n ),\n ),\n\n discover: (handle: QuickJSHandle, opts: QuickJSHandle) =>\n vm.exportSingleValue(\n pinHandle(\n driver.discover(\n vm.vm.getString(handle) as CollectionHandle,\n vm.importObjectViaJson(opts) as DiscoverColumnsOptions,\n bindings,\n ),\n ),\n ),\n\n filter: (handle: QuickJSHandle, opts: QuickJSHandle) =>\n vm.exportSingleValue(\n pinHandle(\n driver.filter(\n vm.vm.getString(handle) as CollectionHandle,\n vm.importObjectViaJson(opts) as DiscoverColumnsOptions,\n bindings,\n ),\n ),\n ),\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
2
|
+
//#region src/js_render/spec_override_collapse.ts
|
|
3
|
+
/**
|
|
4
|
+
* Collapse the client-side `specOverride` query node at the host boundary —
|
|
5
|
+
* pframe-engine never sees it. The override is pushed down through the
|
|
6
|
+
* subtree until it lands on `column`-leaf nodes, where it is folded into
|
|
7
|
+
* the leaf's spec via {@link applySpecOverrides}. Intermediate join nodes
|
|
8
|
+
* are left untouched — pframe-engine will recompute their result spec
|
|
9
|
+
* from the patched leaves.
|
|
10
|
+
*
|
|
11
|
+
* Designed to run as the `node` visitor in `mapPTableDefV2` (post-order),
|
|
12
|
+
* so by the time we see a `specOverride` its inner subtree is already
|
|
13
|
+
* mapped to {@link PColumn} leaves.
|
|
14
|
+
*
|
|
15
|
+
* Currently only `column` and `linkerJoin` are walked. Other node shapes
|
|
16
|
+
* under `specOverride` throw — pframe-engine support for them is still
|
|
17
|
+
* in progress. Extend the switch in {@link pushSpecOverrideDown} as more
|
|
18
|
+
* shapes become needed.
|
|
19
|
+
*/
|
|
20
|
+
function collapseSpecOverrideNode(node) {
|
|
21
|
+
if (node.type !== "specOverride") return node;
|
|
22
|
+
return pushSpecOverrideDown(node.input, node.override);
|
|
23
|
+
}
|
|
24
|
+
function pushSpecOverrideDown(node, overrides) {
|
|
25
|
+
switch (node.type) {
|
|
26
|
+
case "column": return {
|
|
27
|
+
type: "column",
|
|
28
|
+
column: {
|
|
29
|
+
...node.column,
|
|
30
|
+
spec: (0, _milaboratories_pl_model_common.applySpecOverrides)(node.column.spec, overrides)
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
case "linkerJoin": {
|
|
34
|
+
const { axesSpec: _axesSpec, ...nonAxesOverrides } = overrides;
|
|
35
|
+
const hasNonAxes = nonAxesOverrides.domain !== void 0 || nonAxesOverrides.contextDomain !== void 0 || nonAxesOverrides.annotations !== void 0;
|
|
36
|
+
return {
|
|
37
|
+
...node,
|
|
38
|
+
linker: hasNonAxes ? pushSpecOverrideDown(node.linker, nonAxesOverrides) : node.linker,
|
|
39
|
+
secondary: node.secondary.map((e) => ({
|
|
40
|
+
...e,
|
|
41
|
+
entry: pushSpecOverrideDown(e.entry, overrides)
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
case "sliceAxes": {
|
|
46
|
+
if (overrides.axesSpec === void 0 || Object.keys(overrides.axesSpec).length === 0) return {
|
|
47
|
+
...node,
|
|
48
|
+
input: pushSpecOverrideDown(node.input, overrides)
|
|
49
|
+
};
|
|
50
|
+
const innerAxes = effectiveAxesSpec(node.input);
|
|
51
|
+
if (innerAxes === void 0) throw new Error(`specOverride over sliceAxes: cannot translate axesSpec — inner shape unknown for input type "${node.input.type}"`);
|
|
52
|
+
const filteredInnerIdxs = /* @__PURE__ */ new Set();
|
|
53
|
+
for (const filter of node.axisFilters) {
|
|
54
|
+
const idx = innerAxes.findIndex((a) => (0, _milaboratories_pl_model_common.matchAxis)(filter.axisSelector, a));
|
|
55
|
+
if (idx < 0) throw new Error(`specOverride over sliceAxes: filter selector ${JSON.stringify(filter.axisSelector)} not found in inner axes`);
|
|
56
|
+
filteredInnerIdxs.add(idx);
|
|
57
|
+
}
|
|
58
|
+
const outerToInner = [];
|
|
59
|
+
for (let i = 0; i < innerAxes.length; i++) if (!filteredInnerIdxs.has(i)) outerToInner.push(i);
|
|
60
|
+
const translated = {};
|
|
61
|
+
for (const [outerKey, patch] of Object.entries(overrides.axesSpec)) {
|
|
62
|
+
const outerIdx = Number(outerKey);
|
|
63
|
+
const innerIdx = outerToInner[outerIdx];
|
|
64
|
+
if (innerIdx === void 0) throw new Error(`specOverride over sliceAxes: outer axesSpec index ${outerIdx} out of range (slice output has ${outerToInner.length} axes)`);
|
|
65
|
+
translated[innerIdx] = patch;
|
|
66
|
+
}
|
|
67
|
+
const translatedOverrides = {
|
|
68
|
+
...overrides,
|
|
69
|
+
axesSpec: translated
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
...node,
|
|
73
|
+
input: pushSpecOverrideDown(node.input, translatedOverrides)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
default: throw new Error(`specOverride: inner node "${node.type}" is not supported yet — only column / linkerJoin can carry an override (pframe-engine support for the rest is in progress)`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Effective post-traversal {@link AxesSpec} of a {@link Node} — used to
|
|
81
|
+
* translate positional axesSpec patches across structural nodes whose
|
|
82
|
+
* indexing differs from their input (currently only `sliceAxes`).
|
|
83
|
+
*
|
|
84
|
+
* Returns `undefined` when the node shape is not introspectable here.
|
|
85
|
+
* Callers must then refuse axesSpec translation and surface a clear error,
|
|
86
|
+
* rather than silently mis-targeting indices.
|
|
87
|
+
*/
|
|
88
|
+
function effectiveAxesSpec(node) {
|
|
89
|
+
switch (node.type) {
|
|
90
|
+
case "column": return node.column.spec.axesSpec;
|
|
91
|
+
case "linkerJoin": return node.secondary.length === 0 ? void 0 : effectiveAxesSpec(node.secondary[0].entry);
|
|
92
|
+
case "sliceAxes": {
|
|
93
|
+
const inner = effectiveAxesSpec(node.input);
|
|
94
|
+
if (inner === void 0) return void 0;
|
|
95
|
+
const filtered = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const f of node.axisFilters) {
|
|
97
|
+
const i = inner.findIndex((a) => (0, _milaboratories_pl_model_common.matchAxis)(f.axisSelector, a));
|
|
98
|
+
if (i >= 0) filtered.add(i);
|
|
99
|
+
}
|
|
100
|
+
return inner.filter((_, i) => !filtered.has(i));
|
|
101
|
+
}
|
|
102
|
+
default: return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
exports.collapseSpecOverrideNode = collapseSpecOverrideNode;
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=spec_override_collapse.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec_override_collapse.cjs","names":[],"sources":["../../src/js_render/spec_override_collapse.ts"],"sourcesContent":["import type { PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { DataInfo, PColumn, PColumnValues } from \"@platforma-sdk/model\";\nimport { applySpecOverrides, matchAxis } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesSpec,\n AxisPatches,\n SpecOverrides,\n SpecQuery,\n} from \"@milaboratories/pl-model-common\";\n\ntype Leaf = PColumn<PlTreeNodeAccessor | PColumnValues | DataInfo<PlTreeNodeAccessor>>;\ntype Node = SpecQuery<Leaf>;\n\n/**\n * Collapse the client-side `specOverride` query node at the host boundary —\n * pframe-engine never sees it. The override is pushed down through the\n * subtree until it lands on `column`-leaf nodes, where it is folded into\n * the leaf's spec via {@link applySpecOverrides}. Intermediate join nodes\n * are left untouched — pframe-engine will recompute their result spec\n * from the patched leaves.\n *\n * Designed to run as the `node` visitor in `mapPTableDefV2` (post-order),\n * so by the time we see a `specOverride` its inner subtree is already\n * mapped to {@link PColumn} leaves.\n *\n * Currently only `column` and `linkerJoin` are walked. Other node shapes\n * under `specOverride` throw — pframe-engine support for them is still\n * in progress. Extend the switch in {@link pushSpecOverrideDown} as more\n * shapes become needed.\n */\nexport function collapseSpecOverrideNode(node: Node): Node {\n if (node.type !== \"specOverride\") return node;\n return pushSpecOverrideDown(node.input, node.override);\n}\n\nfunction pushSpecOverrideDown(node: Node, overrides: SpecOverrides): Node {\n switch (node.type) {\n case \"column\":\n return {\n type: \"column\",\n column: { ...node.column, spec: applySpecOverrides(node.column.spec, overrides) },\n };\n\n case \"linkerJoin\": {\n // `axesSpec` patches are positional against the linkerJoin's OUTPUT axes,\n // which equal the secondary side's axes (ColumnDiscoveredRecipe emits the\n // hit on the many-side of the linker). Route axesSpec only into secondary;\n // applying the same positional indices to the linker would silently\n // mis-target the linker's own axes.\n //\n // Non-axesSpec patches (domain / contextDomain / annotations) are\n // column-level and not positional — keep the existing both-sides walk.\n const { axesSpec: _axesSpec, ...nonAxesOverrides } = overrides;\n const hasNonAxes =\n nonAxesOverrides.domain !== undefined ||\n nonAxesOverrides.contextDomain !== undefined ||\n nonAxesOverrides.annotations !== undefined;\n return {\n ...node,\n linker: hasNonAxes ? pushSpecOverrideDown(node.linker, nonAxesOverrides) : node.linker,\n secondary: node.secondary.map((e) => ({\n ...e,\n entry: pushSpecOverrideDown(e.entry, overrides),\n })),\n };\n }\n\n // case \"outerJoin\":\n // return {\n // ...node,\n // primary: {\n // ...node.primary,\n // entry: pushSpecOverrideDown(node.primary.entry, overrides),\n // },\n // secondary: node.secondary.map((e) => ({\n // ...e,\n // entry: pushSpecOverrideDown(e.entry, overrides),\n // })),\n // };\n\n // case \"innerJoin\":\n // case \"fullJoin\":\n // case \"symmetricJoin\":\n // return {\n // ...node,\n // entries: node.entries.map((e) => ({\n // ...e,\n // entry: pushSpecOverrideDown(e.entry, overrides),\n // })),\n // };\n\n case \"sliceAxes\": {\n // axesSpec patches are positional against the slice OUTPUT axes (the\n // recipe-layer spec the consumer sees), but the inner input still\n // carries the full pre-slice axes list. Translate outer indices to\n // inner indices before pushing the override down.\n //\n // Non-axesSpec overrides (domain / contextDomain / annotations) are\n // column-level and pass through transparently.\n if (overrides.axesSpec === undefined || Object.keys(overrides.axesSpec).length === 0) {\n return { ...node, input: pushSpecOverrideDown(node.input, overrides) };\n }\n\n const innerAxes = effectiveAxesSpec(node.input);\n if (innerAxes === undefined) {\n throw new Error(\n `specOverride over sliceAxes: cannot translate axesSpec — ` +\n `inner shape unknown for input type \"${node.input.type}\"`,\n );\n }\n\n const filteredInnerIdxs = new Set<number>();\n for (const filter of node.axisFilters) {\n const idx = innerAxes.findIndex((a) => matchAxis(filter.axisSelector, a));\n if (idx < 0) {\n throw new Error(\n `specOverride over sliceAxes: filter selector ` +\n `${JSON.stringify(filter.axisSelector)} not found in inner axes`,\n );\n }\n filteredInnerIdxs.add(idx);\n }\n\n // outer index j (post-slice) ↔ inner index = j-th surviving position.\n const outerToInner: number[] = [];\n for (let i = 0; i < innerAxes.length; i++) {\n if (!filteredInnerIdxs.has(i)) outerToInner.push(i);\n }\n\n const translated: AxisPatches = {};\n for (const [outerKey, patch] of Object.entries(overrides.axesSpec)) {\n const outerIdx = Number(outerKey);\n const innerIdx = outerToInner[outerIdx];\n if (innerIdx === undefined) {\n throw new Error(\n `specOverride over sliceAxes: outer axesSpec index ${outerIdx} ` +\n `out of range (slice output has ${outerToInner.length} axes)`,\n );\n }\n translated[innerIdx] = patch;\n }\n\n const translatedOverrides: SpecOverrides = { ...overrides, axesSpec: translated };\n return { ...node, input: pushSpecOverrideDown(node.input, translatedOverrides) };\n }\n\n // // Transparent transforms — passthrough.\n // case \"sort\":\n // case \"filter\":\n // case \"transformColumns\":\n // return { ...node, input: pushSpecOverrideDown(node.input, overrides) };\n\n // // Synthetic leaves — patch the spec carrier they expose, or\n // // throw if the node has no natural place to absorb overrides.\n // case \"inlineColumn\":\n // return {\n // ...node,\n // column: { ...node.column, spec: applySpecOverrides(node.column.spec, overrides) },\n // };\n\n // case \"sparseToDenseColumn\":\n // // Same idea: patch the new dense column's spec carrier.\n // return {\n // ...node,\n // newSpec: applySpecOverrides(node.newSpec, overrides),\n // };\n\n default:\n throw new Error(\n `specOverride: inner node \"${node.type}\" is not supported yet — ` +\n \"only column / linkerJoin can carry an override \" +\n \"(pframe-engine support for the rest is in progress)\",\n );\n }\n}\n\n/**\n * Effective post-traversal {@link AxesSpec} of a {@link Node} — used to\n * translate positional axesSpec patches across structural nodes whose\n * indexing differs from their input (currently only `sliceAxes`).\n *\n * Returns `undefined` when the node shape is not introspectable here.\n * Callers must then refuse axesSpec translation and surface a clear error,\n * rather than silently mis-targeting indices.\n */\nfunction effectiveAxesSpec(node: Node): AxesSpec | undefined {\n switch (node.type) {\n case \"column\":\n return node.column.spec.axesSpec;\n\n case \"linkerJoin\":\n // Output axes equal the secondary side's axes (linker side drops out).\n // All secondary entries share the same axis identity post-join — read\n // the first one.\n return node.secondary.length === 0 ? undefined : effectiveAxesSpec(node.secondary[0].entry);\n\n case \"sliceAxes\": {\n const inner = effectiveAxesSpec(node.input);\n if (inner === undefined) return undefined;\n const filtered = new Set<number>();\n for (const f of node.axisFilters) {\n const i = inner.findIndex((a) => matchAxis(f.axisSelector, a));\n if (i >= 0) filtered.add(i);\n }\n return inner.filter((_, i) => !filtered.has(i));\n }\n\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { applySpecOverrides, matchAxis } from "@milaboratories/pl-model-common";
|
|
2
|
+
//#region src/js_render/spec_override_collapse.ts
|
|
3
|
+
/**
|
|
4
|
+
* Collapse the client-side `specOverride` query node at the host boundary —
|
|
5
|
+
* pframe-engine never sees it. The override is pushed down through the
|
|
6
|
+
* subtree until it lands on `column`-leaf nodes, where it is folded into
|
|
7
|
+
* the leaf's spec via {@link applySpecOverrides}. Intermediate join nodes
|
|
8
|
+
* are left untouched — pframe-engine will recompute their result spec
|
|
9
|
+
* from the patched leaves.
|
|
10
|
+
*
|
|
11
|
+
* Designed to run as the `node` visitor in `mapPTableDefV2` (post-order),
|
|
12
|
+
* so by the time we see a `specOverride` its inner subtree is already
|
|
13
|
+
* mapped to {@link PColumn} leaves.
|
|
14
|
+
*
|
|
15
|
+
* Currently only `column` and `linkerJoin` are walked. Other node shapes
|
|
16
|
+
* under `specOverride` throw — pframe-engine support for them is still
|
|
17
|
+
* in progress. Extend the switch in {@link pushSpecOverrideDown} as more
|
|
18
|
+
* shapes become needed.
|
|
19
|
+
*/
|
|
20
|
+
function collapseSpecOverrideNode(node) {
|
|
21
|
+
if (node.type !== "specOverride") return node;
|
|
22
|
+
return pushSpecOverrideDown(node.input, node.override);
|
|
23
|
+
}
|
|
24
|
+
function pushSpecOverrideDown(node, overrides) {
|
|
25
|
+
switch (node.type) {
|
|
26
|
+
case "column": return {
|
|
27
|
+
type: "column",
|
|
28
|
+
column: {
|
|
29
|
+
...node.column,
|
|
30
|
+
spec: applySpecOverrides(node.column.spec, overrides)
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
case "linkerJoin": {
|
|
34
|
+
const { axesSpec: _axesSpec, ...nonAxesOverrides } = overrides;
|
|
35
|
+
const hasNonAxes = nonAxesOverrides.domain !== void 0 || nonAxesOverrides.contextDomain !== void 0 || nonAxesOverrides.annotations !== void 0;
|
|
36
|
+
return {
|
|
37
|
+
...node,
|
|
38
|
+
linker: hasNonAxes ? pushSpecOverrideDown(node.linker, nonAxesOverrides) : node.linker,
|
|
39
|
+
secondary: node.secondary.map((e) => ({
|
|
40
|
+
...e,
|
|
41
|
+
entry: pushSpecOverrideDown(e.entry, overrides)
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
case "sliceAxes": {
|
|
46
|
+
if (overrides.axesSpec === void 0 || Object.keys(overrides.axesSpec).length === 0) return {
|
|
47
|
+
...node,
|
|
48
|
+
input: pushSpecOverrideDown(node.input, overrides)
|
|
49
|
+
};
|
|
50
|
+
const innerAxes = effectiveAxesSpec(node.input);
|
|
51
|
+
if (innerAxes === void 0) throw new Error(`specOverride over sliceAxes: cannot translate axesSpec — inner shape unknown for input type "${node.input.type}"`);
|
|
52
|
+
const filteredInnerIdxs = /* @__PURE__ */ new Set();
|
|
53
|
+
for (const filter of node.axisFilters) {
|
|
54
|
+
const idx = innerAxes.findIndex((a) => matchAxis(filter.axisSelector, a));
|
|
55
|
+
if (idx < 0) throw new Error(`specOverride over sliceAxes: filter selector ${JSON.stringify(filter.axisSelector)} not found in inner axes`);
|
|
56
|
+
filteredInnerIdxs.add(idx);
|
|
57
|
+
}
|
|
58
|
+
const outerToInner = [];
|
|
59
|
+
for (let i = 0; i < innerAxes.length; i++) if (!filteredInnerIdxs.has(i)) outerToInner.push(i);
|
|
60
|
+
const translated = {};
|
|
61
|
+
for (const [outerKey, patch] of Object.entries(overrides.axesSpec)) {
|
|
62
|
+
const outerIdx = Number(outerKey);
|
|
63
|
+
const innerIdx = outerToInner[outerIdx];
|
|
64
|
+
if (innerIdx === void 0) throw new Error(`specOverride over sliceAxes: outer axesSpec index ${outerIdx} out of range (slice output has ${outerToInner.length} axes)`);
|
|
65
|
+
translated[innerIdx] = patch;
|
|
66
|
+
}
|
|
67
|
+
const translatedOverrides = {
|
|
68
|
+
...overrides,
|
|
69
|
+
axesSpec: translated
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
...node,
|
|
73
|
+
input: pushSpecOverrideDown(node.input, translatedOverrides)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
default: throw new Error(`specOverride: inner node "${node.type}" is not supported yet — only column / linkerJoin can carry an override (pframe-engine support for the rest is in progress)`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Effective post-traversal {@link AxesSpec} of a {@link Node} — used to
|
|
81
|
+
* translate positional axesSpec patches across structural nodes whose
|
|
82
|
+
* indexing differs from their input (currently only `sliceAxes`).
|
|
83
|
+
*
|
|
84
|
+
* Returns `undefined` when the node shape is not introspectable here.
|
|
85
|
+
* Callers must then refuse axesSpec translation and surface a clear error,
|
|
86
|
+
* rather than silently mis-targeting indices.
|
|
87
|
+
*/
|
|
88
|
+
function effectiveAxesSpec(node) {
|
|
89
|
+
switch (node.type) {
|
|
90
|
+
case "column": return node.column.spec.axesSpec;
|
|
91
|
+
case "linkerJoin": return node.secondary.length === 0 ? void 0 : effectiveAxesSpec(node.secondary[0].entry);
|
|
92
|
+
case "sliceAxes": {
|
|
93
|
+
const inner = effectiveAxesSpec(node.input);
|
|
94
|
+
if (inner === void 0) return void 0;
|
|
95
|
+
const filtered = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const f of node.axisFilters) {
|
|
97
|
+
const i = inner.findIndex((a) => matchAxis(f.axisSelector, a));
|
|
98
|
+
if (i >= 0) filtered.add(i);
|
|
99
|
+
}
|
|
100
|
+
return inner.filter((_, i) => !filtered.has(i));
|
|
101
|
+
}
|
|
102
|
+
default: return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { collapseSpecOverrideNode };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=spec_override_collapse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec_override_collapse.js","names":[],"sources":["../../src/js_render/spec_override_collapse.ts"],"sourcesContent":["import type { PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { DataInfo, PColumn, PColumnValues } from \"@platforma-sdk/model\";\nimport { applySpecOverrides, matchAxis } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesSpec,\n AxisPatches,\n SpecOverrides,\n SpecQuery,\n} from \"@milaboratories/pl-model-common\";\n\ntype Leaf = PColumn<PlTreeNodeAccessor | PColumnValues | DataInfo<PlTreeNodeAccessor>>;\ntype Node = SpecQuery<Leaf>;\n\n/**\n * Collapse the client-side `specOverride` query node at the host boundary —\n * pframe-engine never sees it. The override is pushed down through the\n * subtree until it lands on `column`-leaf nodes, where it is folded into\n * the leaf's spec via {@link applySpecOverrides}. Intermediate join nodes\n * are left untouched — pframe-engine will recompute their result spec\n * from the patched leaves.\n *\n * Designed to run as the `node` visitor in `mapPTableDefV2` (post-order),\n * so by the time we see a `specOverride` its inner subtree is already\n * mapped to {@link PColumn} leaves.\n *\n * Currently only `column` and `linkerJoin` are walked. Other node shapes\n * under `specOverride` throw — pframe-engine support for them is still\n * in progress. Extend the switch in {@link pushSpecOverrideDown} as more\n * shapes become needed.\n */\nexport function collapseSpecOverrideNode(node: Node): Node {\n if (node.type !== \"specOverride\") return node;\n return pushSpecOverrideDown(node.input, node.override);\n}\n\nfunction pushSpecOverrideDown(node: Node, overrides: SpecOverrides): Node {\n switch (node.type) {\n case \"column\":\n return {\n type: \"column\",\n column: { ...node.column, spec: applySpecOverrides(node.column.spec, overrides) },\n };\n\n case \"linkerJoin\": {\n // `axesSpec` patches are positional against the linkerJoin's OUTPUT axes,\n // which equal the secondary side's axes (ColumnDiscoveredRecipe emits the\n // hit on the many-side of the linker). Route axesSpec only into secondary;\n // applying the same positional indices to the linker would silently\n // mis-target the linker's own axes.\n //\n // Non-axesSpec patches (domain / contextDomain / annotations) are\n // column-level and not positional — keep the existing both-sides walk.\n const { axesSpec: _axesSpec, ...nonAxesOverrides } = overrides;\n const hasNonAxes =\n nonAxesOverrides.domain !== undefined ||\n nonAxesOverrides.contextDomain !== undefined ||\n nonAxesOverrides.annotations !== undefined;\n return {\n ...node,\n linker: hasNonAxes ? pushSpecOverrideDown(node.linker, nonAxesOverrides) : node.linker,\n secondary: node.secondary.map((e) => ({\n ...e,\n entry: pushSpecOverrideDown(e.entry, overrides),\n })),\n };\n }\n\n // case \"outerJoin\":\n // return {\n // ...node,\n // primary: {\n // ...node.primary,\n // entry: pushSpecOverrideDown(node.primary.entry, overrides),\n // },\n // secondary: node.secondary.map((e) => ({\n // ...e,\n // entry: pushSpecOverrideDown(e.entry, overrides),\n // })),\n // };\n\n // case \"innerJoin\":\n // case \"fullJoin\":\n // case \"symmetricJoin\":\n // return {\n // ...node,\n // entries: node.entries.map((e) => ({\n // ...e,\n // entry: pushSpecOverrideDown(e.entry, overrides),\n // })),\n // };\n\n case \"sliceAxes\": {\n // axesSpec patches are positional against the slice OUTPUT axes (the\n // recipe-layer spec the consumer sees), but the inner input still\n // carries the full pre-slice axes list. Translate outer indices to\n // inner indices before pushing the override down.\n //\n // Non-axesSpec overrides (domain / contextDomain / annotations) are\n // column-level and pass through transparently.\n if (overrides.axesSpec === undefined || Object.keys(overrides.axesSpec).length === 0) {\n return { ...node, input: pushSpecOverrideDown(node.input, overrides) };\n }\n\n const innerAxes = effectiveAxesSpec(node.input);\n if (innerAxes === undefined) {\n throw new Error(\n `specOverride over sliceAxes: cannot translate axesSpec — ` +\n `inner shape unknown for input type \"${node.input.type}\"`,\n );\n }\n\n const filteredInnerIdxs = new Set<number>();\n for (const filter of node.axisFilters) {\n const idx = innerAxes.findIndex((a) => matchAxis(filter.axisSelector, a));\n if (idx < 0) {\n throw new Error(\n `specOverride over sliceAxes: filter selector ` +\n `${JSON.stringify(filter.axisSelector)} not found in inner axes`,\n );\n }\n filteredInnerIdxs.add(idx);\n }\n\n // outer index j (post-slice) ↔ inner index = j-th surviving position.\n const outerToInner: number[] = [];\n for (let i = 0; i < innerAxes.length; i++) {\n if (!filteredInnerIdxs.has(i)) outerToInner.push(i);\n }\n\n const translated: AxisPatches = {};\n for (const [outerKey, patch] of Object.entries(overrides.axesSpec)) {\n const outerIdx = Number(outerKey);\n const innerIdx = outerToInner[outerIdx];\n if (innerIdx === undefined) {\n throw new Error(\n `specOverride over sliceAxes: outer axesSpec index ${outerIdx} ` +\n `out of range (slice output has ${outerToInner.length} axes)`,\n );\n }\n translated[innerIdx] = patch;\n }\n\n const translatedOverrides: SpecOverrides = { ...overrides, axesSpec: translated };\n return { ...node, input: pushSpecOverrideDown(node.input, translatedOverrides) };\n }\n\n // // Transparent transforms — passthrough.\n // case \"sort\":\n // case \"filter\":\n // case \"transformColumns\":\n // return { ...node, input: pushSpecOverrideDown(node.input, overrides) };\n\n // // Synthetic leaves — patch the spec carrier they expose, or\n // // throw if the node has no natural place to absorb overrides.\n // case \"inlineColumn\":\n // return {\n // ...node,\n // column: { ...node.column, spec: applySpecOverrides(node.column.spec, overrides) },\n // };\n\n // case \"sparseToDenseColumn\":\n // // Same idea: patch the new dense column's spec carrier.\n // return {\n // ...node,\n // newSpec: applySpecOverrides(node.newSpec, overrides),\n // };\n\n default:\n throw new Error(\n `specOverride: inner node \"${node.type}\" is not supported yet — ` +\n \"only column / linkerJoin can carry an override \" +\n \"(pframe-engine support for the rest is in progress)\",\n );\n }\n}\n\n/**\n * Effective post-traversal {@link AxesSpec} of a {@link Node} — used to\n * translate positional axesSpec patches across structural nodes whose\n * indexing differs from their input (currently only `sliceAxes`).\n *\n * Returns `undefined` when the node shape is not introspectable here.\n * Callers must then refuse axesSpec translation and surface a clear error,\n * rather than silently mis-targeting indices.\n */\nfunction effectiveAxesSpec(node: Node): AxesSpec | undefined {\n switch (node.type) {\n case \"column\":\n return node.column.spec.axesSpec;\n\n case \"linkerJoin\":\n // Output axes equal the secondary side's axes (linker side drops out).\n // All secondary entries share the same axis identity post-join — read\n // the first one.\n return node.secondary.length === 0 ? undefined : effectiveAxesSpec(node.secondary[0].entry);\n\n case \"sliceAxes\": {\n const inner = effectiveAxesSpec(node.input);\n if (inner === undefined) return undefined;\n const filtered = new Set<number>();\n for (const f of node.axisFilters) {\n const i = inner.findIndex((a) => matchAxis(f.axisSelector, a));\n if (i >= 0) filtered.add(i);\n }\n return inner.filter((_, i) => !filtered.has(i));\n }\n\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -87,7 +87,8 @@ function constructBlockContext(projectEntry, blockId) {
|
|
|
87
87
|
ignoreError: true
|
|
88
88
|
})?.persist();
|
|
89
89
|
},
|
|
90
|
-
getResultsPool: (cCtx) => require_result_pool.ResultPool.create(cCtx, projectEntry, blockId)
|
|
90
|
+
getResultsPool: (cCtx) => require_result_pool.ResultPool.create(cCtx, projectEntry, blockId),
|
|
91
|
+
projectEntry
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_ctx.cjs","names":["projectFieldName","ProjectStructureKey","allBlocks","ResultPool"],"sources":["../../src/middle_layer/block_ctx.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { cachedDecode, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Optional } from \"utility-types\";\nimport type { Block, ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey, projectFieldName } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\nimport { ResultPool } from \"../pool/result_pool\";\nimport { deriveDataFromStorage } from \"@platforma-sdk/model\";\n\nexport type BlockContextArgsOnly = {\n readonly blockId: string;\n readonly args: (cCtx: ComputableCtx) => string | undefined;\n readonly activeArgs: (cCtx: ComputableCtx) => string | undefined;\n readonly blockMeta: (cCtx: ComputableCtx) => Map<string, Block>;\n readonly data: (cCtx: ComputableCtx) => string | undefined;\n readonly blockStorage: (cCtx: ComputableCtx) => string | undefined;\n readonly prerunArgs: (cCtx: ComputableCtx) => string | undefined;\n};\n\nexport type BlockContextFull = BlockContextArgsOnly & {\n readonly prod: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly staging: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly getResultsPool: (cCtx: ComputableCtx) => ResultPool;\n};\n\nexport type BlockContextAny = Optional
|
|
1
|
+
{"version":3,"file":"block_ctx.cjs","names":["projectFieldName","ProjectStructureKey","allBlocks","ResultPool"],"sources":["../../src/middle_layer/block_ctx.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { cachedDecode, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Optional } from \"utility-types\";\nimport type { Block, ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey, projectFieldName } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\nimport { ResultPool } from \"../pool/result_pool\";\nimport { deriveDataFromStorage } from \"@platforma-sdk/model\";\n\nexport type BlockContextArgsOnly = {\n readonly blockId: string;\n readonly args: (cCtx: ComputableCtx) => string | undefined;\n readonly activeArgs: (cCtx: ComputableCtx) => string | undefined;\n readonly blockMeta: (cCtx: ComputableCtx) => Map<string, Block>;\n readonly data: (cCtx: ComputableCtx) => string | undefined;\n readonly blockStorage: (cCtx: ComputableCtx) => string | undefined;\n readonly prerunArgs: (cCtx: ComputableCtx) => string | undefined;\n};\n\nexport type BlockContextFull = BlockContextArgsOnly & {\n readonly prod: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly staging: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly getResultsPool: (cCtx: ComputableCtx) => ResultPool;\n readonly projectEntry: PlTreeEntry;\n};\n\nexport type BlockContextAny = Optional<\n BlockContextFull,\n \"prod\" | \"staging\" | \"getResultsPool\" | \"projectEntry\"\n>;\n\nexport function constructBlockContextArgsOnly(\n projectEntry: PlTreeEntry,\n blockId: string,\n): BlockContextArgsOnly {\n const args = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"currentArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n const activeArgs = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"prodArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n const data = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"blockStorage\"),\n stableIfNotFound: true,\n })\n ?.getData();\n if (!data) return undefined;\n\n const rawJson = cachedDecode(data);\n if (!rawJson) return undefined;\n\n // Parse to check if it's BlockStorage format\n try {\n const parsed = JSON.parse(rawJson);\n return JSON.stringify(deriveDataFromStorage(parsed));\n } catch (err) {\n console.error(\"Error deriving data from storage\", err);\n return undefined;\n }\n };\n // Returns raw blockStorage JSON - UI derives data using sdk/model\n const blockStorage = (cCtx: ComputableCtx) => {\n const storageData = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"blockStorage\"),\n stableIfNotFound: true,\n })\n ?.getData();\n if (!storageData) return undefined;\n return cachedDecode(storageData);\n };\n const prerunArgs = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"currentPrerunArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n return {\n blockId,\n args,\n activeArgs,\n data,\n blockStorage,\n prerunArgs,\n blockMeta: (cCtx: ComputableCtx) => {\n const prj = cCtx.accessor(projectEntry).node();\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n const result = new Map<string, Block>();\n for (const block of allBlocks(structure)) result.set(block.id, block);\n return result;\n },\n };\n}\n\nexport function constructBlockContext(\n projectEntry: PlTreeEntry,\n blockId: string,\n): BlockContextFull {\n return {\n ...constructBlockContextArgsOnly(projectEntry, blockId),\n prod: (cCtx: ComputableCtx) => {\n return cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"prodOutput\"),\n stableIfNotFound: true,\n ignoreError: true,\n })\n ?.persist();\n },\n staging: (cCtx: ComputableCtx) => {\n // Check if staging is expected (currentPrerunArgs is set)\n // For blocks with failed args derivation, staging will never be rendered\n const hasPrerunArgs =\n cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"currentPrerunArgs\"),\n stableIfNotFound: true,\n ignoreError: true,\n }) !== undefined;\n\n const result = cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"stagingOutput\"),\n // Only mark stable if staging is NOT expected (no prerunArgs)\n stableIfNotFound: !hasPrerunArgs,\n ignoreError: true,\n })\n ?.persist();\n return result;\n },\n getResultsPool: (cCtx: ComputableCtx) => ResultPool.create(cCtx, projectEntry, blockId),\n projectEntry,\n };\n}\n"],"mappings":"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"}
|
|
@@ -87,7 +87,8 @@ function constructBlockContext(projectEntry, blockId) {
|
|
|
87
87
|
ignoreError: true
|
|
88
88
|
})?.persist();
|
|
89
89
|
},
|
|
90
|
-
getResultsPool: (cCtx) => ResultPool.create(cCtx, projectEntry, blockId)
|
|
90
|
+
getResultsPool: (cCtx) => ResultPool.create(cCtx, projectEntry, blockId),
|
|
91
|
+
projectEntry
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_ctx.js","names":[],"sources":["../../src/middle_layer/block_ctx.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { cachedDecode, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Optional } from \"utility-types\";\nimport type { Block, ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey, projectFieldName } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\nimport { ResultPool } from \"../pool/result_pool\";\nimport { deriveDataFromStorage } from \"@platforma-sdk/model\";\n\nexport type BlockContextArgsOnly = {\n readonly blockId: string;\n readonly args: (cCtx: ComputableCtx) => string | undefined;\n readonly activeArgs: (cCtx: ComputableCtx) => string | undefined;\n readonly blockMeta: (cCtx: ComputableCtx) => Map<string, Block>;\n readonly data: (cCtx: ComputableCtx) => string | undefined;\n readonly blockStorage: (cCtx: ComputableCtx) => string | undefined;\n readonly prerunArgs: (cCtx: ComputableCtx) => string | undefined;\n};\n\nexport type BlockContextFull = BlockContextArgsOnly & {\n readonly prod: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly staging: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly getResultsPool: (cCtx: ComputableCtx) => ResultPool;\n};\n\nexport type BlockContextAny = Optional
|
|
1
|
+
{"version":3,"file":"block_ctx.js","names":[],"sources":["../../src/middle_layer/block_ctx.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { cachedDecode, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Optional } from \"utility-types\";\nimport type { Block, ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey, projectFieldName } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\nimport { ResultPool } from \"../pool/result_pool\";\nimport { deriveDataFromStorage } from \"@platforma-sdk/model\";\n\nexport type BlockContextArgsOnly = {\n readonly blockId: string;\n readonly args: (cCtx: ComputableCtx) => string | undefined;\n readonly activeArgs: (cCtx: ComputableCtx) => string | undefined;\n readonly blockMeta: (cCtx: ComputableCtx) => Map<string, Block>;\n readonly data: (cCtx: ComputableCtx) => string | undefined;\n readonly blockStorage: (cCtx: ComputableCtx) => string | undefined;\n readonly prerunArgs: (cCtx: ComputableCtx) => string | undefined;\n};\n\nexport type BlockContextFull = BlockContextArgsOnly & {\n readonly prod: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly staging: (cCtx: ComputableCtx) => PlTreeEntry | undefined;\n readonly getResultsPool: (cCtx: ComputableCtx) => ResultPool;\n readonly projectEntry: PlTreeEntry;\n};\n\nexport type BlockContextAny = Optional<\n BlockContextFull,\n \"prod\" | \"staging\" | \"getResultsPool\" | \"projectEntry\"\n>;\n\nexport function constructBlockContextArgsOnly(\n projectEntry: PlTreeEntry,\n blockId: string,\n): BlockContextArgsOnly {\n const args = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"currentArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n const activeArgs = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"prodArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n const data = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"blockStorage\"),\n stableIfNotFound: true,\n })\n ?.getData();\n if (!data) return undefined;\n\n const rawJson = cachedDecode(data);\n if (!rawJson) return undefined;\n\n // Parse to check if it's BlockStorage format\n try {\n const parsed = JSON.parse(rawJson);\n return JSON.stringify(deriveDataFromStorage(parsed));\n } catch (err) {\n console.error(\"Error deriving data from storage\", err);\n return undefined;\n }\n };\n // Returns raw blockStorage JSON - UI derives data using sdk/model\n const blockStorage = (cCtx: ComputableCtx) => {\n const storageData = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"blockStorage\"),\n stableIfNotFound: true,\n })\n ?.getData();\n if (!storageData) return undefined;\n return cachedDecode(storageData);\n };\n const prerunArgs = (cCtx: ComputableCtx) => {\n const data = cCtx\n .accessor(projectEntry)\n .node()\n .traverse({\n field: projectFieldName(blockId, \"currentPrerunArgs\"),\n stableIfNotFound: true,\n })\n ?.getData();\n return data ? cachedDecode(data) : undefined;\n };\n return {\n blockId,\n args,\n activeArgs,\n data,\n blockStorage,\n prerunArgs,\n blockMeta: (cCtx: ComputableCtx) => {\n const prj = cCtx.accessor(projectEntry).node();\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n const result = new Map<string, Block>();\n for (const block of allBlocks(structure)) result.set(block.id, block);\n return result;\n },\n };\n}\n\nexport function constructBlockContext(\n projectEntry: PlTreeEntry,\n blockId: string,\n): BlockContextFull {\n return {\n ...constructBlockContextArgsOnly(projectEntry, blockId),\n prod: (cCtx: ComputableCtx) => {\n return cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"prodOutput\"),\n stableIfNotFound: true,\n ignoreError: true,\n })\n ?.persist();\n },\n staging: (cCtx: ComputableCtx) => {\n // Check if staging is expected (currentPrerunArgs is set)\n // For blocks with failed args derivation, staging will never be rendered\n const hasPrerunArgs =\n cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"currentPrerunArgs\"),\n stableIfNotFound: true,\n ignoreError: true,\n }) !== undefined;\n\n const result = cCtx\n .accessor(projectEntry)\n .node({ ignoreError: true })\n .traverse({\n field: projectFieldName(blockId, \"stagingOutput\"),\n // Only mark stable if staging is NOT expected (no prerunArgs)\n stableIfNotFound: !hasPrerunArgs,\n ignoreError: true,\n })\n ?.persist();\n return result;\n },\n getResultsPool: (cCtx: ComputableCtx) => ResultPool.create(cCtx, projectEntry, blockId),\n projectEntry,\n };\n}\n"],"mappings":"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"}
|