@platforma-sdk/model 1.58.19 → 1.59.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.
Files changed (35) hide show
  1. package/dist/block_model.cjs +6 -5
  2. package/dist/block_model.cjs.map +1 -1
  3. package/dist/block_model.js +6 -5
  4. package/dist/block_model.js.map +1 -1
  5. package/dist/block_model_legacy.cjs +3 -1
  6. package/dist/block_model_legacy.cjs.map +1 -1
  7. package/dist/block_model_legacy.js +3 -1
  8. package/dist/block_model_legacy.js.map +1 -1
  9. package/dist/components/PlDataTable/labels.cjs +7 -3
  10. package/dist/components/PlDataTable/labels.cjs.map +1 -1
  11. package/dist/components/PlDataTable/labels.js +7 -3
  12. package/dist/components/PlDataTable/labels.js.map +1 -1
  13. package/dist/package.cjs +1 -1
  14. package/dist/package.js +1 -1
  15. package/dist/pframe_utils/axes.cjs +17 -2
  16. package/dist/pframe_utils/axes.cjs.map +1 -1
  17. package/dist/pframe_utils/axes.js +17 -2
  18. package/dist/pframe_utils/axes.js.map +1 -1
  19. package/dist/platforma.d.ts +2 -1
  20. package/dist/render/api.cjs +3 -1
  21. package/dist/render/api.cjs.map +1 -1
  22. package/dist/render/api.js +3 -1
  23. package/dist/render/api.js.map +1 -1
  24. package/dist/render/util/column_collection.cjs +4 -2
  25. package/dist/render/util/column_collection.cjs.map +1 -1
  26. package/dist/render/util/column_collection.js +4 -2
  27. package/dist/render/util/column_collection.js.map +1 -1
  28. package/package.json +5 -5
  29. package/src/block_model.ts +32 -30
  30. package/src/block_model_legacy.ts +6 -3
  31. package/src/components/PlDataTable/labels.ts +17 -4
  32. package/src/pframe_utils/axes.ts +23 -1
  33. package/src/platforma.ts +2 -0
  34. package/src/render/api.ts +9 -1
  35. package/src/render/util/column_collection.ts +13 -7
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection.js","names":[],"sources":["../../../src/render/util/column_collection.ts"],"sourcesContent":["import type {\n AnchoredIdDeriver,\n AnchoredPColumnSelector,\n AxisFilterByIdx,\n AxisFilterValue,\n AxisId,\n NativePObjectId,\n PartitionedDataInfoEntries,\n PColumn,\n PColumnLazy,\n PColumnSelector,\n PColumnSpec,\n PColumnValues,\n PObjectId,\n ResolveAnchorsOptions,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport {\n Annotation,\n canonicalizeAxisId,\n deriveNativeId,\n entriesToDataInfo,\n getAxisId,\n getColumnIdAndSpec,\n isLinkerColumn,\n isPartitionedDataInfoEntries,\n isPColumnSpec,\n LinkerMap,\n matchAxisId,\n resolveAnchors,\n selectorsToPredicate,\n} from \"@milaboratories/pl-model-common\";\nimport canonicalize from \"canonicalize\";\nimport type { Optional } from \"utility-types\";\nimport type { TreeNodeAccessor } from \"../accessor\";\nimport type { PColumnDataUniversal } from \"../internal\";\nimport { filterDataInfoEntries } from \"./axis_filtering\";\nimport type { LabelDerivationOps, TraceEntry } from \"./label\";\nimport { deriveLabels } from \"./label\";\nimport { convertOrParsePColumnData, getUniquePartitionKeys } from \"./pcolumn_data\";\nimport type { APColumnSelectorWithSplit, PColumnSelectorWithSplit } from \"./split_selectors\";\n\nfunction isPColumnValues(value: unknown): value is PColumnValues {\n if (!Array.isArray(value)) return false;\n if (value.length === 0) return true;\n const first = value[0];\n return typeof first === \"object\" && first !== null && \"key\" in first && \"val\" in first;\n}\n\nexport interface ColumnProvider {\n selectColumns(\n selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],\n ): PColumn<PColumnDataUniversal | undefined>[];\n}\n\nexport interface AxisLabelProvider {\n findLabels(axis: AxisId): Record<string | number, string> | undefined;\n}\n\n/**\n * A simple implementation of {@link ColumnProvider} backed by a pre-defined array of columns.\n */\nclass ArrayColumnProvider implements ColumnProvider {\n constructor(private readonly columns: PColumn<PColumnDataUniversal | undefined>[]) {}\n\n selectColumns(\n selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],\n ): PColumn<PColumnDataUniversal | undefined>[] {\n const predicate = typeof selectors === \"function\" ? selectors : selectorsToPredicate(selectors);\n // Filter based on spec, ignoring data type for now\n return this.columns.filter((column): column is PColumn<PColumnDataUniversal | undefined> =>\n predicate(column.spec),\n );\n }\n}\n\n/** Lazy calculates the data, returns undefined if data is not ready. */\nexport type PColumnLazyWithLabel<T> = PColumnLazy<T> & {\n label: string;\n};\n\n/** Universal column is a column that uses a universal column id, and always have label. */\nexport type PColumnLazyUniversal<T> = PColumnLazyWithLabel<T> & {\n id: SUniversalPColumnId;\n};\n\n/** @deprecated Use PColumnLazyWithLabel instead. */\nexport type PColumnEntryWithLabel = PColumnLazy<undefined | PColumnDataUniversal> & {\n label: string;\n};\n\n/** @deprecated Use PColumnLazyUniversal instead. */\nexport type PColumnEntryUniversal = PColumnEntryWithLabel & {\n id: SUniversalPColumnId;\n};\n\n// Helper types similar to those in api.ts\ntype AxisFilterInfo = {\n axisIdx: number;\n axisId: AxisId;\n value: AxisFilterValue;\n label: string;\n};\n\n// Intermediate representation for columns requiring splitting\ntype IntermediateSplitEntry = {\n type: \"split\";\n originalColumn: PColumn<PColumnDataUniversal | undefined>;\n spec: PColumnSpec;\n /** With splitting axes removed */\n adjustedSpec: PColumnSpec;\n dataEntries: PartitionedDataInfoEntries<TreeNodeAccessor>;\n axisFilters: AxisFilterInfo[];\n};\n\n// Intermediate representation for columns NOT requiring splitting\ntype IntermediateDirectEntry = {\n type: \"direct\";\n originalColumn: PColumn<PColumnDataUniversal | undefined>;\n spec: PColumnSpec;\n /** The same as `spec` */\n adjustedSpec: PColumnSpec;\n};\n\n// Union type for intermediate processing\ntype IntermediateColumnEntry = IntermediateSplitEntry | IntermediateDirectEntry;\n\nfunction splitFiltersToTrace(splitFilters?: AxisFilterInfo[]): TraceEntry[] | undefined {\n if (!splitFilters) return undefined;\n return splitFilters.map((filter) => ({\n type: `split:${canonicalizeAxisId(filter.axisId)}`,\n label: filter.label,\n importance: 1_000_000, // High importance for split filters in labels\n }));\n}\n\nfunction splitFiltersToAxisFilter(splitFilters?: AxisFilterInfo[]): AxisFilterByIdx[] | undefined {\n if (!splitFilters) return undefined;\n return splitFilters.map((filter): AxisFilterByIdx => [filter.axisIdx, filter.value]);\n}\n\nfunction fallbackIdDeriver(originalId: PObjectId, axisFilters?: AxisFilterByIdx[]): PObjectId {\n if (!axisFilters || axisFilters.length === 0) return originalId;\n const filtersToCanonicalize = [...axisFilters].sort((a, b) => a[0] - b[0]);\n return canonicalize({ id: originalId, axisFilters: filtersToCanonicalize })! as PObjectId;\n}\n\n/** Checks if a selector object uses any anchor properties */\nfunction hasAnchors(selector: unknown): selector is AnchoredPColumnSelector {\n if (!selector || typeof selector !== \"object\") return false;\n const potentialAnchored = selector as Record<string, any>;\n const domainHasAnchors =\n potentialAnchored[\"domain\"] &&\n typeof potentialAnchored[\"domain\"] === \"object\" &&\n Object.values(potentialAnchored[\"domain\"]).some(\n (v: unknown) => typeof v === \"object\" && v !== null && \"anchor\" in v,\n );\n const axesHaveAnchors =\n potentialAnchored[\"axes\"] &&\n Array.isArray(potentialAnchored[\"axes\"]) &&\n potentialAnchored[\"axes\"].some(\n (a: unknown) => typeof a === \"object\" && a !== null && \"anchor\" in a,\n );\n return !!potentialAnchored[\"domainAnchor\"] || domainHasAnchors || axesHaveAnchors;\n}\n\n/**\n * Derives the indices of axes marked for splitting based on the selector.\n * Throws an error if splitting is requested alongside `partialAxesMatch`.\n */\nfunction getSplitAxisIndices(\n selector: APColumnSelectorWithSplit | ((spec: PColumnSpec) => boolean),\n): number[] {\n if (typeof selector !== \"object\" || !(\"axes\" in selector) || selector.axes === undefined) {\n return []; // No axes specified or not an object selector, no splitting\n }\n\n const splitIndices = selector.axes\n .map((axis, index) =>\n typeof axis === \"object\" && \"split\" in axis && axis.split === true ? index : -1,\n )\n .filter((index) => index !== -1);\n\n if (splitIndices.length > 0 && selector.partialAxesMatch !== undefined) {\n throw new Error(\"Axis splitting is not supported when `partialAxesMatch` is defined.\");\n }\n\n splitIndices.sort((a, b) => a - b);\n return splitIndices;\n}\n\ntype UniversalPColumnOptsNoDeriver = {\n /** If provided, columns matching the provided selectors will be excluded from the result. */\n exclude?: AnchoredPColumnSelector | AnchoredPColumnSelector[];\n labelOps?: LabelDerivationOps;\n /** If true, incomplete data will cause the column to be skipped instead of returning undefined for the whole request. */\n dontWaitAllData?: boolean;\n /**\n * If true, the derived label will override the 'pl7.app/label' annotation\n * in the resulting PColumnSpec. It also forces `includeNativeLabel` in `labelOps` to true,\n * unless `labelOps.includeNativeLabel` is explicitly set to false.\n * Default value in getUniversalEntries is false, in getColumns it is true.\n */\n overrideLabelAnnotation?: boolean;\n /** If true, resulting columns will be enriched by other columns considering linker columns. Default is false. */\n enrichByLinkers?: boolean;\n};\n\ntype UniversalPColumnOpts = UniversalPColumnOptsNoDeriver & {\n anchorCtx: AnchoredIdDeriver;\n} & ResolveAnchorsOptions;\n\nexport class PColumnCollection {\n private readonly defaultProviderStore: PColumn<PColumnDataUniversal | undefined>[] = [];\n private readonly providers: ColumnProvider[] = [\n new ArrayColumnProvider(this.defaultProviderStore),\n ];\n private readonly axisLabelProviders: AxisLabelProvider[] = [];\n\n constructor() {}\n\n public addColumnProvider(provider: ColumnProvider): this {\n this.providers.push(provider);\n return this;\n }\n\n public addAxisLabelProvider(provider: AxisLabelProvider): this {\n this.axisLabelProviders.push(provider);\n return this;\n }\n\n public addColumns(columns: PColumn<PColumnDataUniversal | undefined>[]): this {\n this.defaultProviderStore.push(...columns);\n return this;\n }\n\n public addColumn(column: PColumn<PColumnDataUniversal | undefined>): this {\n this.defaultProviderStore.push(column);\n return this;\n }\n\n /** Fetches labels for a given axis from the registered providers */\n private findLabels(axis: AxisId): Record<string | number, string> | undefined {\n for (const provider of this.axisLabelProviders) {\n const labels = provider.findLabels(axis);\n if (labels) return labels; // First provider wins\n }\n return undefined;\n }\n\n // Overload signatures updated to return PColumnEntry types\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts: UniversalPColumnOpts,\n ): PColumnEntryUniversal[] | undefined;\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | PColumnSelectorWithSplit\n | PColumnSelectorWithSplit[],\n opts?: UniversalPColumnOptsNoDeriver,\n ): PColumnEntryWithLabel[] | undefined;\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts?: Optional<UniversalPColumnOpts, \"anchorCtx\">,\n ): (PColumnEntryWithLabel | PColumnEntryUniversal)[] | undefined {\n const {\n anchorCtx,\n labelOps: rawLabelOps,\n dontWaitAllData = false,\n overrideLabelAnnotation = false,\n exclude,\n enrichByLinkers = false,\n } = opts ?? {};\n\n const labelOps: LabelDerivationOps = {\n ...(overrideLabelAnnotation && rawLabelOps?.includeNativeLabel !== false\n ? { includeNativeLabel: true }\n : {}),\n ...rawLabelOps,\n };\n\n let excludePredicate: (spec: PColumnSpec) => boolean = () => false;\n if (exclude) {\n const excludePredicartes = (Array.isArray(exclude) ? exclude : [exclude]).map((selector) => {\n if (hasAnchors(selector)) {\n if (!anchorCtx)\n throw new Error(\n \"Anchored selectors in exclude require an AnchoredIdDeriver to be provided in options.\",\n );\n return selectorsToPredicate(resolveAnchors(anchorCtx.anchors, selector, opts));\n } else return selectorsToPredicate(selector);\n });\n excludePredicate = (spec) => excludePredicartes.some((predicate) => predicate(spec));\n }\n\n const selectorsArray =\n typeof predicateOrSelectors === \"function\"\n ? [predicateOrSelectors]\n : Array.isArray(predicateOrSelectors)\n ? predicateOrSelectors\n : [predicateOrSelectors];\n\n const intermediateResults: IntermediateColumnEntry[] = [];\n const selectedNativeIds = new Set<NativePObjectId>();\n\n for (const rawSelector of selectorsArray) {\n const usesAnchors = hasAnchors(rawSelector);\n\n let currentSelector: PColumnSelectorWithSplit | ((spec: PColumnSpec) => boolean);\n if (usesAnchors) {\n if (!anchorCtx)\n throw new Error(\n \"Anchored selectors require an AnchoredIdDeriver to be provided in options.\",\n );\n currentSelector = resolveAnchors(\n anchorCtx.anchors,\n rawSelector as AnchoredPColumnSelector,\n opts,\n );\n } else\n currentSelector = rawSelector as\n | PColumnSelectorWithSplit\n | ((spec: PColumnSpec) => boolean);\n\n const selectedIds = new Set<PObjectId>();\n const selectedColumns: PColumn<PColumnDataUniversal | undefined>[] = [];\n for (const provider of this.providers) {\n const providerColumns = provider.selectColumns(currentSelector);\n for (const col of providerColumns) {\n if (excludePredicate(col.spec)) continue;\n if (selectedIds.has(col.id))\n throw new Error(\n `Duplicate column id ${col.id} in provider ${provider.constructor.name}`,\n );\n const nativeId = deriveNativeId(col.spec);\n if (selectedNativeIds.has(nativeId)) continue;\n selectedIds.add(col.id);\n selectedNativeIds.add(nativeId);\n selectedColumns.push(col);\n }\n }\n\n if (selectedColumns.length === 0) continue;\n\n const splitAxisIdxs = getSplitAxisIndices(rawSelector);\n const needsSplitting = splitAxisIdxs.length > 0;\n\n for (const column of selectedColumns) {\n if (!isPColumnSpec(column.spec)) continue;\n\n const originalSpec = column.spec;\n\n if (needsSplitting) {\n if (isPColumnValues(column.data))\n throw new Error(\n `Splitting is not supported for PColumns with PColumnValues data format. Column id: ${column.id}`,\n );\n const dataEntries = convertOrParsePColumnData(column.data);\n\n if (!dataEntries) {\n if (dontWaitAllData) continue;\n return undefined;\n }\n\n if (!isPartitionedDataInfoEntries(dataEntries))\n throw new Error(\n `Splitting requires Partitioned DataInfoEntries, but parsing resulted in ${dataEntries.type} for column ${column.id}`,\n );\n\n const uniqueKeys = getUniquePartitionKeys(dataEntries);\n\n const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];\n if (maxSplitIdx >= dataEntries.partitionKeyLength)\n throw new Error(\n `Not enough partition keys (${dataEntries.partitionKeyLength}) for requested split axes (max index ${maxSplitIdx}) in column ${originalSpec.name}`,\n );\n\n const axesLabels: (Record<string | number, string> | undefined)[] = splitAxisIdxs.map(\n (idx) => this.findLabels(getAxisId(originalSpec.axesSpec[idx])),\n );\n\n const keyCombinations: (string | number)[][] = [];\n const generateCombinations = (currentCombo: (string | number)[], sAxisIdx: number) => {\n if (sAxisIdx >= splitAxisIdxs.length) {\n keyCombinations.push([...currentCombo]);\n if (keyCombinations.length > 10000)\n throw new Error(\"Too many key combinations, aborting.\");\n return;\n }\n const axisIdx = splitAxisIdxs[sAxisIdx];\n if (axisIdx >= uniqueKeys.length)\n throw new Error(\n `Axis index ${axisIdx} out of bounds for unique keys array (length ${uniqueKeys.length}) during split key generation for column ${column.id}`,\n );\n const axisValues = uniqueKeys[axisIdx];\n if (!axisValues || axisValues.length === 0) {\n keyCombinations.length = 0; // No combinations possible if one axis has no keys\n return;\n }\n for (const val of axisValues) {\n currentCombo.push(val);\n generateCombinations(currentCombo, sAxisIdx + 1);\n currentCombo.pop();\n }\n };\n\n generateCombinations([], 0);\n\n if (keyCombinations.length === 0) continue;\n\n const newAxesSpec = [...originalSpec.axesSpec];\n const splitAxisOriginalIdxs = splitAxisIdxs.map((idx) => idx); // Keep original indices for axisId lookup\n // Remove axes in reverse order to maintain correct indices during removal\n for (let i = splitAxisIdxs.length - 1; i >= 0; i--) {\n newAxesSpec.splice(splitAxisIdxs[i], 1);\n }\n const adjustedSpec = { ...originalSpec, axesSpec: newAxesSpec };\n\n for (const keyCombo of keyCombinations) {\n const splitFilters: AxisFilterInfo[] = keyCombo.map((value, sAxisIdx) => {\n const axisIdx = splitAxisOriginalIdxs[sAxisIdx]; // Use original index for lookup\n const axisId = getAxisId(originalSpec.axesSpec[axisIdx]);\n const axisLabelMap = axesLabels[sAxisIdx];\n const label = axisLabelMap?.[value] ?? String(value);\n return { axisIdx, axisId, value: value as AxisFilterValue, label };\n });\n\n intermediateResults.push({\n type: \"split\",\n originalColumn: column,\n spec: originalSpec,\n adjustedSpec,\n dataEntries,\n axisFilters: splitFilters,\n });\n }\n } else {\n intermediateResults.push({\n type: \"direct\",\n originalColumn: column,\n spec: originalSpec,\n adjustedSpec: originalSpec,\n });\n }\n }\n }\n\n if (intermediateResults.length === 0) return [];\n\n const labeledResults = deriveLabels(\n intermediateResults,\n (entry) => ({\n spec: entry.spec,\n suffixTrace: entry.type === \"split\" ? splitFiltersToTrace(entry.axisFilters) : undefined,\n }),\n labelOps,\n );\n\n const result: (PColumnEntryWithLabel | PColumnEntryUniversal)[] = [];\n\n for (const { value: entry, label } of labeledResults) {\n const { originalColumn, spec: originalSpec } = entry;\n\n const axisFilters = entry.type === \"split\" ? entry.axisFilters : undefined;\n const axisFiltersTuple = splitFiltersToAxisFilter(axisFilters);\n\n let finalId: SUniversalPColumnId | PObjectId;\n if (anchorCtx) finalId = anchorCtx.deriveS(originalSpec, axisFiltersTuple);\n else finalId = fallbackIdDeriver(originalColumn.id, axisFiltersTuple);\n\n let finalSpec = { ...entry.adjustedSpec };\n\n if (overrideLabelAnnotation) {\n finalSpec = {\n ...finalSpec,\n annotations: {\n ...finalSpec.annotations,\n [Annotation.Label]: label,\n } satisfies Annotation,\n };\n }\n\n result.push({\n id: finalId,\n spec: finalSpec,\n data: () =>\n entry.type === \"split\"\n ? entriesToDataInfo(filterDataInfoEntries(entry.dataEntries, axisFiltersTuple!))\n : entry.originalColumn.data,\n label: label,\n });\n }\n\n const ids = new Set(result.map((entry) => entry.id));\n\n if (enrichByLinkers && anchorCtx) {\n const linkers = result.filter((entry) => isLinkerColumn(entry.spec));\n if (linkers.length === 0) {\n return result;\n }\n\n const anchorAxes = Object.values(anchorCtx.anchors).flatMap((anchor) => anchor.axesSpec);\n const linkerMap = LinkerMap.fromColumns(linkers.map(getColumnIdAndSpec));\n\n // loose way of matching\n function matchAxisIdFn(linkerKeyId: AxisId, sourceAxisId: AxisId): boolean {\n return matchAxisId(linkerKeyId, sourceAxisId) || matchAxisId(sourceAxisId, linkerKeyId);\n }\n // search all axes that can be reached by linkers from anchor axes; anchor axes are not in this list;\n const availableByLinkersAxes = linkerMap.getReachableByLinkersAxesFromAxes(\n anchorAxes,\n matchAxisIdFn,\n );\n\n // search all columns that includes at least one of additional axes;\n const availableByLinkersColumns = this.getUniversalEntries(\n (spec) =>\n !isLinkerColumn(spec) &&\n spec.axesSpec.some((columnAxisSpec) => {\n const columnAxisId = getAxisId(columnAxisSpec);\n return availableByLinkersAxes.some((axis) =>\n matchAxisIdFn(getAxisId(axis), columnAxisId),\n );\n }),\n { anchorCtx, labelOps, dontWaitAllData, overrideLabelAnnotation, exclude },\n );\n if (availableByLinkersColumns) {\n result.push(...availableByLinkersColumns.filter((entry) => !ids.has(entry.id)));\n }\n }\n\n return result;\n }\n\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts: UniversalPColumnOpts,\n ): PColumn<PColumnDataUniversal>[] | undefined;\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | PColumnSelectorWithSplit\n | PColumnSelectorWithSplit[],\n opts?: UniversalPColumnOptsNoDeriver,\n ): PColumn<PColumnDataUniversal>[] | undefined;\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts?: Optional<UniversalPColumnOpts, \"anchorCtx\">,\n ): PColumn<PColumnDataUniversal>[] | undefined {\n const entries = this.getUniversalEntries(predicateOrSelectors, {\n overrideLabelAnnotation: true, // default for getColumns\n ...opts,\n } as UniversalPColumnOpts);\n if (!entries) return undefined;\n\n const columns: PColumn<PColumnDataUniversal>[] = [];\n for (const entry of entries) {\n const data = entry.data();\n if (!data) {\n if (opts?.dontWaitAllData) continue;\n return undefined;\n }\n columns.push({\n id: entry.id,\n spec: entry.spec,\n data,\n });\n }\n\n return columns;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column_collection.js","names":[],"sources":["../../../src/render/util/column_collection.ts"],"sourcesContent":["import type {\n AnchoredIdDeriver,\n AnchoredPColumnSelector,\n AxisFilterByIdx,\n AxisFilterValue,\n AxisId,\n NativePObjectId,\n PartitionedDataInfoEntries,\n PColumn,\n PColumnLazy,\n PColumnSelector,\n PColumnSpec,\n PColumnValues,\n PObjectId,\n ResolveAnchorsOptions,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport {\n Annotation,\n canonicalizeAxisId,\n deriveNativeId,\n entriesToDataInfo,\n getAxisId,\n getColumnIdAndSpec,\n isLinkerColumn,\n isPartitionedDataInfoEntries,\n isPColumnSpec,\n LinkerMap,\n matchAxisId,\n resolveAnchors,\n selectorsToPredicate,\n} from \"@milaboratories/pl-model-common\";\nimport canonicalize from \"canonicalize\";\nimport type { Optional } from \"utility-types\";\nimport type { TreeNodeAccessor } from \"../accessor\";\nimport type { PColumnDataUniversal } from \"../internal\";\nimport { filterDataInfoEntries } from \"./axis_filtering\";\nimport type { LabelDerivationOps, TraceEntry } from \"./label\";\nimport { deriveLabels } from \"./label\";\nimport { convertOrParsePColumnData, getUniquePartitionKeys } from \"./pcolumn_data\";\nimport type { APColumnSelectorWithSplit, PColumnSelectorWithSplit } from \"./split_selectors\";\n\nfunction isPColumnValues(value: unknown): value is PColumnValues {\n if (!Array.isArray(value)) return false;\n if (value.length === 0) return true;\n const first = value[0];\n return typeof first === \"object\" && first !== null && \"key\" in first && \"val\" in first;\n}\n\nexport interface ColumnProvider {\n selectColumns(\n selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],\n ): PColumn<PColumnDataUniversal | undefined>[];\n}\n\nexport interface AxisLabelProvider {\n findLabels(axis: AxisId): Record<string | number, string> | undefined;\n}\n\n/**\n * A simple implementation of {@link ColumnProvider} backed by a pre-defined array of columns.\n */\nclass ArrayColumnProvider implements ColumnProvider {\n constructor(private readonly columns: PColumn<PColumnDataUniversal | undefined>[]) {}\n\n selectColumns(\n selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],\n ): PColumn<PColumnDataUniversal | undefined>[] {\n const predicate = typeof selectors === \"function\" ? selectors : selectorsToPredicate(selectors);\n // Filter based on spec, ignoring data type for now\n return this.columns.filter((column): column is PColumn<PColumnDataUniversal | undefined> =>\n predicate(column.spec),\n );\n }\n}\n\n/** Lazy calculates the data, returns undefined if data is not ready. */\nexport type PColumnLazyWithLabel<T> = PColumnLazy<T> & {\n label: string;\n};\n\n/** Universal column is a column that uses a universal column id, and always have label. */\nexport type PColumnLazyUniversal<T> = PColumnLazyWithLabel<T> & {\n id: SUniversalPColumnId;\n};\n\n/** @deprecated Use PColumnLazyWithLabel instead. */\nexport type PColumnEntryWithLabel = PColumnLazy<undefined | PColumnDataUniversal> & {\n label: string;\n};\n\n/** @deprecated Use PColumnLazyUniversal instead. */\nexport type PColumnEntryUniversal = PColumnEntryWithLabel & {\n id: SUniversalPColumnId;\n};\n\n// Helper types similar to those in api.ts\ntype AxisFilterInfo = {\n axisIdx: number;\n axisId: AxisId;\n value: AxisFilterValue;\n label: string;\n};\n\n// Intermediate representation for columns requiring splitting\ntype IntermediateSplitEntry = {\n type: \"split\";\n originalColumn: PColumn<PColumnDataUniversal | undefined>;\n spec: PColumnSpec;\n /** With splitting axes removed */\n adjustedSpec: PColumnSpec;\n dataEntries: PartitionedDataInfoEntries<TreeNodeAccessor>;\n axisFilters: AxisFilterInfo[];\n};\n\n// Intermediate representation for columns NOT requiring splitting\ntype IntermediateDirectEntry = {\n type: \"direct\";\n originalColumn: PColumn<PColumnDataUniversal | undefined>;\n spec: PColumnSpec;\n /** The same as `spec` */\n adjustedSpec: PColumnSpec;\n};\n\n// Union type for intermediate processing\ntype IntermediateColumnEntry = IntermediateSplitEntry | IntermediateDirectEntry;\n\nfunction splitFiltersToTrace(splitFilters?: AxisFilterInfo[]): TraceEntry[] | undefined {\n if (!splitFilters) return undefined;\n return splitFilters.map((filter) => ({\n type: `split:${canonicalizeAxisId(filter.axisId)}`,\n label: filter.label,\n importance: 1_000_000, // High importance for split filters in labels\n }));\n}\n\nfunction splitFiltersToAxisFilter(splitFilters?: AxisFilterInfo[]): AxisFilterByIdx[] | undefined {\n if (!splitFilters) return undefined;\n return splitFilters.map((filter): AxisFilterByIdx => [filter.axisIdx, filter.value]);\n}\n\nfunction fallbackIdDeriver(originalId: PObjectId, axisFilters?: AxisFilterByIdx[]): PObjectId {\n if (!axisFilters || axisFilters.length === 0) return originalId;\n const filtersToCanonicalize = [...axisFilters].sort((a, b) => a[0] - b[0]);\n return canonicalize({ id: originalId, axisFilters: filtersToCanonicalize })! as PObjectId;\n}\n\n/** Checks if a selector object uses any anchor properties */\nfunction hasAnchors(selector: unknown): selector is AnchoredPColumnSelector {\n if (!selector || typeof selector !== \"object\") return false;\n const potentialAnchored = selector as Record<string, any>;\n const hasAnchorValues = (obj: unknown) =>\n obj &&\n typeof obj === \"object\" &&\n Object.values(obj).some((v: unknown) => typeof v === \"object\" && v !== null && \"anchor\" in v);\n const domainHasAnchors = hasAnchorValues(potentialAnchored[\"domain\"]);\n const contextDomainHasAnchors = hasAnchorValues(potentialAnchored[\"contextDomain\"]);\n const axesHaveAnchors =\n potentialAnchored[\"axes\"] &&\n Array.isArray(potentialAnchored[\"axes\"]) &&\n potentialAnchored[\"axes\"].some(\n (a: unknown) => typeof a === \"object\" && a !== null && \"anchor\" in a,\n );\n return (\n !!potentialAnchored[\"domainAnchor\"] ||\n !!potentialAnchored[\"contextDomainAnchor\"] ||\n domainHasAnchors ||\n contextDomainHasAnchors ||\n axesHaveAnchors\n );\n}\n\n/**\n * Derives the indices of axes marked for splitting based on the selector.\n * Throws an error if splitting is requested alongside `partialAxesMatch`.\n */\nfunction getSplitAxisIndices(\n selector: APColumnSelectorWithSplit | ((spec: PColumnSpec) => boolean),\n): number[] {\n if (typeof selector !== \"object\" || !(\"axes\" in selector) || selector.axes === undefined) {\n return []; // No axes specified or not an object selector, no splitting\n }\n\n const splitIndices = selector.axes\n .map((axis, index) =>\n typeof axis === \"object\" && \"split\" in axis && axis.split === true ? index : -1,\n )\n .filter((index) => index !== -1);\n\n if (splitIndices.length > 0 && selector.partialAxesMatch !== undefined) {\n throw new Error(\"Axis splitting is not supported when `partialAxesMatch` is defined.\");\n }\n\n splitIndices.sort((a, b) => a - b);\n return splitIndices;\n}\n\ntype UniversalPColumnOptsNoDeriver = {\n /** If provided, columns matching the provided selectors will be excluded from the result. */\n exclude?: AnchoredPColumnSelector | AnchoredPColumnSelector[];\n labelOps?: LabelDerivationOps;\n /** If true, incomplete data will cause the column to be skipped instead of returning undefined for the whole request. */\n dontWaitAllData?: boolean;\n /**\n * If true, the derived label will override the 'pl7.app/label' annotation\n * in the resulting PColumnSpec. It also forces `includeNativeLabel` in `labelOps` to true,\n * unless `labelOps.includeNativeLabel` is explicitly set to false.\n * Default value in getUniversalEntries is false, in getColumns it is true.\n */\n overrideLabelAnnotation?: boolean;\n /** If true, resulting columns will be enriched by other columns considering linker columns. Default is false. */\n enrichByLinkers?: boolean;\n};\n\ntype UniversalPColumnOpts = UniversalPColumnOptsNoDeriver & {\n anchorCtx: AnchoredIdDeriver;\n} & ResolveAnchorsOptions;\n\nexport class PColumnCollection {\n private readonly defaultProviderStore: PColumn<PColumnDataUniversal | undefined>[] = [];\n private readonly providers: ColumnProvider[] = [\n new ArrayColumnProvider(this.defaultProviderStore),\n ];\n private readonly axisLabelProviders: AxisLabelProvider[] = [];\n\n constructor() {}\n\n public addColumnProvider(provider: ColumnProvider): this {\n this.providers.push(provider);\n return this;\n }\n\n public addAxisLabelProvider(provider: AxisLabelProvider): this {\n this.axisLabelProviders.push(provider);\n return this;\n }\n\n public addColumns(columns: PColumn<PColumnDataUniversal | undefined>[]): this {\n this.defaultProviderStore.push(...columns);\n return this;\n }\n\n public addColumn(column: PColumn<PColumnDataUniversal | undefined>): this {\n this.defaultProviderStore.push(column);\n return this;\n }\n\n /** Fetches labels for a given axis from the registered providers */\n private findLabels(axis: AxisId): Record<string | number, string> | undefined {\n for (const provider of this.axisLabelProviders) {\n const labels = provider.findLabels(axis);\n if (labels) return labels; // First provider wins\n }\n return undefined;\n }\n\n // Overload signatures updated to return PColumnEntry types\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts: UniversalPColumnOpts,\n ): PColumnEntryUniversal[] | undefined;\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | PColumnSelectorWithSplit\n | PColumnSelectorWithSplit[],\n opts?: UniversalPColumnOptsNoDeriver,\n ): PColumnEntryWithLabel[] | undefined;\n public getUniversalEntries(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts?: Optional<UniversalPColumnOpts, \"anchorCtx\">,\n ): (PColumnEntryWithLabel | PColumnEntryUniversal)[] | undefined {\n const {\n anchorCtx,\n labelOps: rawLabelOps,\n dontWaitAllData = false,\n overrideLabelAnnotation = false,\n exclude,\n enrichByLinkers = false,\n } = opts ?? {};\n\n const labelOps: LabelDerivationOps = {\n ...(overrideLabelAnnotation && rawLabelOps?.includeNativeLabel !== false\n ? { includeNativeLabel: true }\n : {}),\n ...rawLabelOps,\n };\n\n let excludePredicate: (spec: PColumnSpec) => boolean = () => false;\n if (exclude) {\n const excludePredicartes = (Array.isArray(exclude) ? exclude : [exclude]).map((selector) => {\n if (hasAnchors(selector)) {\n if (!anchorCtx)\n throw new Error(\n \"Anchored selectors in exclude require an AnchoredIdDeriver to be provided in options.\",\n );\n return selectorsToPredicate(resolveAnchors(anchorCtx.anchors, selector, opts));\n } else return selectorsToPredicate(selector);\n });\n excludePredicate = (spec) => excludePredicartes.some((predicate) => predicate(spec));\n }\n\n const selectorsArray =\n typeof predicateOrSelectors === \"function\"\n ? [predicateOrSelectors]\n : Array.isArray(predicateOrSelectors)\n ? predicateOrSelectors\n : [predicateOrSelectors];\n\n const intermediateResults: IntermediateColumnEntry[] = [];\n const selectedNativeIds = new Set<NativePObjectId>();\n\n for (const rawSelector of selectorsArray) {\n const usesAnchors = hasAnchors(rawSelector);\n\n let currentSelector: PColumnSelectorWithSplit | ((spec: PColumnSpec) => boolean);\n if (usesAnchors) {\n if (!anchorCtx)\n throw new Error(\n \"Anchored selectors require an AnchoredIdDeriver to be provided in options.\",\n );\n currentSelector = resolveAnchors(\n anchorCtx.anchors,\n rawSelector as AnchoredPColumnSelector,\n opts,\n );\n } else\n currentSelector = rawSelector as\n | PColumnSelectorWithSplit\n | ((spec: PColumnSpec) => boolean);\n\n const selectedIds = new Set<PObjectId>();\n const selectedColumns: PColumn<PColumnDataUniversal | undefined>[] = [];\n for (const provider of this.providers) {\n const providerColumns = provider.selectColumns(currentSelector);\n for (const col of providerColumns) {\n if (excludePredicate(col.spec)) continue;\n if (selectedIds.has(col.id))\n throw new Error(\n `Duplicate column id ${col.id} in provider ${provider.constructor.name}`,\n );\n const nativeId = deriveNativeId(col.spec);\n if (selectedNativeIds.has(nativeId)) continue;\n selectedIds.add(col.id);\n selectedNativeIds.add(nativeId);\n selectedColumns.push(col);\n }\n }\n\n if (selectedColumns.length === 0) continue;\n\n const splitAxisIdxs = getSplitAxisIndices(rawSelector);\n const needsSplitting = splitAxisIdxs.length > 0;\n\n for (const column of selectedColumns) {\n if (!isPColumnSpec(column.spec)) continue;\n\n const originalSpec = column.spec;\n\n if (needsSplitting) {\n if (isPColumnValues(column.data))\n throw new Error(\n `Splitting is not supported for PColumns with PColumnValues data format. Column id: ${column.id}`,\n );\n const dataEntries = convertOrParsePColumnData(column.data);\n\n if (!dataEntries) {\n if (dontWaitAllData) continue;\n return undefined;\n }\n\n if (!isPartitionedDataInfoEntries(dataEntries))\n throw new Error(\n `Splitting requires Partitioned DataInfoEntries, but parsing resulted in ${dataEntries.type} for column ${column.id}`,\n );\n\n const uniqueKeys = getUniquePartitionKeys(dataEntries);\n\n const maxSplitIdx = splitAxisIdxs[splitAxisIdxs.length - 1];\n if (maxSplitIdx >= dataEntries.partitionKeyLength)\n throw new Error(\n `Not enough partition keys (${dataEntries.partitionKeyLength}) for requested split axes (max index ${maxSplitIdx}) in column ${originalSpec.name}`,\n );\n\n const axesLabels: (Record<string | number, string> | undefined)[] = splitAxisIdxs.map(\n (idx) => this.findLabels(getAxisId(originalSpec.axesSpec[idx])),\n );\n\n const keyCombinations: (string | number)[][] = [];\n const generateCombinations = (currentCombo: (string | number)[], sAxisIdx: number) => {\n if (sAxisIdx >= splitAxisIdxs.length) {\n keyCombinations.push([...currentCombo]);\n if (keyCombinations.length > 10000)\n throw new Error(\"Too many key combinations, aborting.\");\n return;\n }\n const axisIdx = splitAxisIdxs[sAxisIdx];\n if (axisIdx >= uniqueKeys.length)\n throw new Error(\n `Axis index ${axisIdx} out of bounds for unique keys array (length ${uniqueKeys.length}) during split key generation for column ${column.id}`,\n );\n const axisValues = uniqueKeys[axisIdx];\n if (!axisValues || axisValues.length === 0) {\n keyCombinations.length = 0; // No combinations possible if one axis has no keys\n return;\n }\n for (const val of axisValues) {\n currentCombo.push(val);\n generateCombinations(currentCombo, sAxisIdx + 1);\n currentCombo.pop();\n }\n };\n\n generateCombinations([], 0);\n\n if (keyCombinations.length === 0) continue;\n\n const newAxesSpec = [...originalSpec.axesSpec];\n const splitAxisOriginalIdxs = splitAxisIdxs.map((idx) => idx); // Keep original indices for axisId lookup\n // Remove axes in reverse order to maintain correct indices during removal\n for (let i = splitAxisIdxs.length - 1; i >= 0; i--) {\n newAxesSpec.splice(splitAxisIdxs[i], 1);\n }\n const adjustedSpec = { ...originalSpec, axesSpec: newAxesSpec };\n\n for (const keyCombo of keyCombinations) {\n const splitFilters: AxisFilterInfo[] = keyCombo.map((value, sAxisIdx) => {\n const axisIdx = splitAxisOriginalIdxs[sAxisIdx]; // Use original index for lookup\n const axisId = getAxisId(originalSpec.axesSpec[axisIdx]);\n const axisLabelMap = axesLabels[sAxisIdx];\n const label = axisLabelMap?.[value] ?? String(value);\n return { axisIdx, axisId, value: value as AxisFilterValue, label };\n });\n\n intermediateResults.push({\n type: \"split\",\n originalColumn: column,\n spec: originalSpec,\n adjustedSpec,\n dataEntries,\n axisFilters: splitFilters,\n });\n }\n } else {\n intermediateResults.push({\n type: \"direct\",\n originalColumn: column,\n spec: originalSpec,\n adjustedSpec: originalSpec,\n });\n }\n }\n }\n\n if (intermediateResults.length === 0) return [];\n\n const labeledResults = deriveLabels(\n intermediateResults,\n (entry) => ({\n spec: entry.spec,\n suffixTrace: entry.type === \"split\" ? splitFiltersToTrace(entry.axisFilters) : undefined,\n }),\n labelOps,\n );\n\n const result: (PColumnEntryWithLabel | PColumnEntryUniversal)[] = [];\n\n for (const { value: entry, label } of labeledResults) {\n const { originalColumn, spec: originalSpec } = entry;\n\n const axisFilters = entry.type === \"split\" ? entry.axisFilters : undefined;\n const axisFiltersTuple = splitFiltersToAxisFilter(axisFilters);\n\n let finalId: SUniversalPColumnId | PObjectId;\n if (anchorCtx) finalId = anchorCtx.deriveS(originalSpec, axisFiltersTuple);\n else finalId = fallbackIdDeriver(originalColumn.id, axisFiltersTuple);\n\n let finalSpec = { ...entry.adjustedSpec };\n\n if (overrideLabelAnnotation) {\n finalSpec = {\n ...finalSpec,\n annotations: {\n ...finalSpec.annotations,\n [Annotation.Label]: label,\n } satisfies Annotation,\n };\n }\n\n result.push({\n id: finalId,\n spec: finalSpec,\n data: () =>\n entry.type === \"split\"\n ? entriesToDataInfo(filterDataInfoEntries(entry.dataEntries, axisFiltersTuple!))\n : entry.originalColumn.data,\n label: label,\n });\n }\n\n const ids = new Set(result.map((entry) => entry.id));\n\n if (enrichByLinkers && anchorCtx) {\n const linkers = result.filter((entry) => isLinkerColumn(entry.spec));\n if (linkers.length === 0) {\n return result;\n }\n\n const anchorAxes = Object.values(anchorCtx.anchors).flatMap((anchor) => anchor.axesSpec);\n const linkerMap = LinkerMap.fromColumns(linkers.map(getColumnIdAndSpec));\n\n // loose way of matching\n function matchAxisIdFn(linkerKeyId: AxisId, sourceAxisId: AxisId): boolean {\n return matchAxisId(linkerKeyId, sourceAxisId) || matchAxisId(sourceAxisId, linkerKeyId);\n }\n // search all axes that can be reached by linkers from anchor axes; anchor axes are not in this list;\n const availableByLinkersAxes = linkerMap.getReachableByLinkersAxesFromAxes(\n anchorAxes,\n matchAxisIdFn,\n );\n\n // search all columns that includes at least one of additional axes;\n const availableByLinkersColumns = this.getUniversalEntries(\n (spec) =>\n !isLinkerColumn(spec) &&\n spec.axesSpec.some((columnAxisSpec) => {\n const columnAxisId = getAxisId(columnAxisSpec);\n return availableByLinkersAxes.some((axis) =>\n matchAxisIdFn(getAxisId(axis), columnAxisId),\n );\n }),\n { anchorCtx, labelOps, dontWaitAllData, overrideLabelAnnotation, exclude },\n );\n if (availableByLinkersColumns) {\n result.push(...availableByLinkersColumns.filter((entry) => !ids.has(entry.id)));\n }\n }\n\n return result;\n }\n\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts: UniversalPColumnOpts,\n ): PColumn<PColumnDataUniversal>[] | undefined;\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | PColumnSelectorWithSplit\n | PColumnSelectorWithSplit[],\n opts?: UniversalPColumnOptsNoDeriver,\n ): PColumn<PColumnDataUniversal>[] | undefined;\n public getColumns(\n predicateOrSelectors:\n | ((spec: PColumnSpec) => boolean)\n | APColumnSelectorWithSplit\n | APColumnSelectorWithSplit[],\n opts?: Optional<UniversalPColumnOpts, \"anchorCtx\">,\n ): PColumn<PColumnDataUniversal>[] | undefined {\n const entries = this.getUniversalEntries(predicateOrSelectors, {\n overrideLabelAnnotation: true, // default for getColumns\n ...opts,\n } as UniversalPColumnOpts);\n if (!entries) return undefined;\n\n const columns: PColumn<PColumnDataUniversal>[] = [];\n for (const entry of entries) {\n const data = entry.data();\n if (!data) {\n if (opts?.dontWaitAllData) continue;\n return undefined;\n }\n columns.push({\n id: entry.id,\n spec: entry.spec,\n data,\n });\n }\n\n return columns;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.58.19",
3
+ "version": "1.59.0",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -30,19 +30,19 @@
30
30
  "fast-json-patch": "^3.1.1",
31
31
  "utility-types": "^3.11.0",
32
32
  "zod": "~3.23.8",
33
- "@milaboratories/pl-model-common": "1.25.2",
34
33
  "@milaboratories/helpers": "1.13.7",
35
34
  "@milaboratories/pl-error-like": "1.12.9",
36
- "@milaboratories/ptabler-expression-js": "1.1.24"
35
+ "@milaboratories/pl-model-common": "1.26.0",
36
+ "@milaboratories/ptabler-expression-js": "1.1.26"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@vitest/coverage-istanbul": "^4.0.18",
40
40
  "fast-json-patch": "^3.1.1",
41
41
  "typescript": "~5.9.3",
42
42
  "vitest": "^4.0.18",
43
- "@milaboratories/ts-builder": "1.3.0",
43
+ "@milaboratories/build-configs": "1.5.2",
44
44
  "@milaboratories/ts-configs": "1.2.2",
45
- "@milaboratories/build-configs": "1.5.2"
45
+ "@milaboratories/ts-builder": "1.3.0"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "ts-builder build --target node",
@@ -130,6 +130,7 @@ export class BlockModelV3<
130
130
 
131
131
  public static readonly INITIAL_BLOCK_FEATURE_FLAGS: BlockCodeKnownFeatureFlags = {
132
132
  supportsLazyState: true,
133
+ supportsPframeQueryRanking: true,
133
134
  requiresUIAPIVersion: 3,
134
135
  requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,
135
136
  requiresCreatePTable: 2,
@@ -558,41 +559,40 @@ export class BlockModelV3<
558
559
  }
559
560
  const allOutputs = { ...this.config.outputs, ...pluginOutputs };
560
561
 
561
- const blockConfig: BlockConfigContainer = {
562
- v4: {
563
- configVersion: 4,
564
- modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,
562
+ globalThis.platformaApiVersion = apiVersion;
563
+
564
+ if (!isInUI()) {
565
+ const blockConfig: BlockConfigContainer = {
566
+ v4: {
567
+ configVersion: 4,
568
+ modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,
569
+ sdkVersion: PlatformaSDKVersion,
570
+ renderingMode: this.config.renderingMode,
571
+ sections: this.config.sections,
572
+ title: this.config.title,
573
+ subtitle: this.config.subtitle,
574
+ tags: this.config.tags,
575
+ outputs: allOutputs,
576
+ enrichmentTargets: this.config.enrichmentTargets,
577
+ featureFlags: this.config.featureFlags,
578
+ blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },
579
+ },
580
+
581
+ // fields below are added to allow previous desktop versions read generated configs
565
582
  sdkVersion: PlatformaSDKVersion,
566
583
  renderingMode: this.config.renderingMode,
567
584
  sections: this.config.sections,
568
- title: this.config.title,
569
- subtitle: this.config.subtitle,
570
- tags: this.config.tags,
571
- outputs: allOutputs,
572
- enrichmentTargets: this.config.enrichmentTargets,
573
- featureFlags: this.config.featureFlags,
574
- blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },
575
- },
576
-
577
- // fields below are added to allow previous desktop versions read generated configs
578
- sdkVersion: PlatformaSDKVersion,
579
- renderingMode: this.config.renderingMode,
580
- sections: this.config.sections,
581
- outputs: Object.fromEntries(
582
- Object.entries(this.config.outputs).map(([key, value]) => [
583
- key,
584
- downgradeCfgOrLambda(value),
585
- ]),
586
- ),
587
- };
588
-
589
- globalThis.platformaApiVersion = apiVersion;
590
-
591
- if (!isInUI())
585
+ outputs: Object.fromEntries(
586
+ Object.entries(this.config.outputs).map(([key, value]) => [
587
+ key,
588
+ downgradeCfgOrLambda(value),
589
+ ]),
590
+ ),
591
+ };
592
592
  // we are in the configuration rendering routine, not in actual UI
593
593
  return { config: blockConfig } as any;
594
- // normal operation inside the UI
595
- else
594
+ // normal operation inside the UI
595
+ } else {
596
596
  return {
597
597
  ...getPlatformaInstance({
598
598
  sdkVersion: PlatformaSDKVersion,
@@ -608,8 +608,10 @@ export class BlockModelV3<
608
608
  ]),
609
609
  ),
610
610
  pluginIds: pluginHandles,
611
+ featureFlags: this.config.featureFlags,
611
612
  },
612
613
  } as any;
614
+ }
613
615
  }
614
616
  }
615
617
 
@@ -68,6 +68,7 @@ export class BlockModel<
68
68
  public static get INITIAL_BLOCK_FEATURE_FLAGS(): BlockCodeKnownFeatureFlags {
69
69
  return {
70
70
  supportsLazyState: true,
71
+ supportsPframeQueryRanking: true,
71
72
  requiresUIAPIVersion: 1,
72
73
  requiresModelAPIVersion: 1,
73
74
  requiresCreatePTable: 2,
@@ -433,11 +434,11 @@ export class BlockModel<
433
434
  globalThis.platformaApiVersion = this.config.featureFlags
434
435
  .requiresUIAPIVersion as PlatformaApiVersion;
435
436
 
436
- if (!isInUI())
437
+ if (!isInUI()) {
437
438
  // we are in the configuration rendering routine, not in actual UI
438
439
  return { config } as any;
439
- // normal operation inside the UI
440
- else
440
+ } else {
441
+ // normal operation inside the UI
441
442
  return {
442
443
  ...getPlatformaInstance({
443
444
  sdkVersion: PlatformaSDKVersion,
@@ -453,7 +454,9 @@ export class BlockModel<
453
454
  ]),
454
455
  ),
455
456
  pluginIds: [],
457
+ featureFlags: this.config.featureFlags,
456
458
  },
457
459
  };
460
+ }
458
461
  }
459
462
  }
@@ -61,7 +61,11 @@ export function getMatchingLabelColumns(
61
61
  }
62
62
 
63
63
  // warning: changing this id will break backward compatibility
64
- const colId = (id: PObjectId, domain?: Record<string, string>): PObjectId => {
64
+ const colId = (
65
+ id: PObjectId,
66
+ domain?: Record<string, string>,
67
+ contextDomain?: Record<string, string>,
68
+ ): PObjectId => {
65
69
  let wid = id.toString();
66
70
  if (domain) {
67
71
  for (const k in domain) {
@@ -69,6 +73,12 @@ export function getMatchingLabelColumns(
69
73
  wid += domain[k];
70
74
  }
71
75
  }
76
+ if (contextDomain) {
77
+ for (const k in contextDomain) {
78
+ wid += k;
79
+ wid += contextDomain[k];
80
+ }
81
+ }
72
82
  return wid as PObjectId;
73
83
  };
74
84
 
@@ -80,11 +90,14 @@ export function getMatchingLabelColumns(
80
90
  const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));
81
91
  if (labelMatch !== -1) {
82
92
  const axisId = unlabeledAxes[labelMatch];
83
- const dataDomainLen = Object.keys(axisId.domain ?? {}).length;
84
- const labelDomainLen = Object.keys(labelAxis.domain ?? {}).length;
93
+ const dataDomainLen =
94
+ Object.keys(axisId.domain ?? {}).length + Object.keys(axisId.contextDomain ?? {}).length;
95
+ const labelDomainLen =
96
+ Object.keys(labelAxis.domain ?? {}).length +
97
+ Object.keys(labelAxis.contextDomain ?? {}).length;
85
98
  if (dataDomainLen > labelDomainLen) {
86
99
  labelColumns.push({
87
- id: colId(labelColumn.id, axisId.domain),
100
+ id: colId(labelColumn.id, axisId.domain, axisId.contextDomain),
88
101
  spec: {
89
102
  ...labelColumn.spec,
90
103
  axesSpec: [{ ...axisId, annotations: labelAxis.annotations }],
@@ -29,7 +29,11 @@ import type { PColumnDataUniversal } from "../render";
29
29
  export type AxesVault = Map<CanonicalizedJson<AxisId>, AxisSpecNormalized>;
30
30
 
31
31
  /** Create id for column copy with added keys in axes domains */
32
- const colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) => {
32
+ const colId = (
33
+ id: PObjectId,
34
+ domains: (Record<string, string> | undefined)[],
35
+ contextDomains: (Record<string, string> | undefined)[],
36
+ ) => {
33
37
  let wid = id.toString();
34
38
  domains?.forEach((domain) => {
35
39
  if (domain) {
@@ -39,6 +43,14 @@ const colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) =
39
43
  }
40
44
  }
41
45
  });
46
+ contextDomains?.forEach((contextDomain) => {
47
+ if (contextDomain) {
48
+ for (const [k, v] of Object.entries(contextDomain)) {
49
+ wid += k;
50
+ wid += v;
51
+ }
52
+ }
53
+ });
42
54
  return wid;
43
55
  };
44
56
 
@@ -122,6 +134,15 @@ function getAdditionalColumnsForColumn<T extends Omit<PColumn<PColumnDataUnivers
122
134
  allAddedDomainValues.add(item);
123
135
  }
124
136
  });
137
+ const cd1 = column.spec.axesSpec[idx].contextDomain;
138
+ const cd2 = axisId.contextDomain;
139
+ Object.entries(cd2 ?? {}).forEach(([key, value]) => {
140
+ if (cd1?.[key] === undefined) {
141
+ const item = JSON.stringify(["ctx:" + key, value]);
142
+ addedSet.add(item);
143
+ allAddedDomainValues.add(item);
144
+ }
145
+ });
125
146
  return {
126
147
  ...axisId,
127
148
  annotations: column.spec.axesSpec[idx].annotations,
@@ -139,6 +160,7 @@ function getAdditionalColumnsForColumn<T extends Omit<PColumn<PColumnDataUnivers
139
160
  const id = colId(
140
161
  column.id,
141
162
  idsList.map((id) => id.domain),
163
+ idsList.map((id) => id.contextDomain),
142
164
  );
143
165
 
144
166
  const label = readAnnotation(column.spec, Annotation.Label) ?? "";
package/src/platforma.ts CHANGED
@@ -2,6 +2,7 @@ import type { BlockApiV1 } from "./block_api_v1";
2
2
  import type { BlockApiV2 } from "./block_api_v2";
3
3
  import type { BlockApiV3 } from "./block_api_v3";
4
4
  import type {
5
+ BlockCodeKnownFeatureFlags,
5
6
  BlockOutputsBase,
6
7
  BlockStateV3,
7
8
  DriverKit,
@@ -87,6 +88,7 @@ export type BlockModelInfo = {
87
88
  }
88
89
  >;
89
90
  pluginIds: PluginHandle[];
91
+ featureFlags: BlockCodeKnownFeatureFlags;
90
92
  };
91
93
 
92
94
  export type PlatformaApiVersion = Platforma["apiVersion"];
package/src/render/api.ts CHANGED
@@ -423,6 +423,10 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
423
423
  continue;
424
424
  }
425
425
 
426
+ if (!matchDomain(spec.contextDomain, oth.contextDomain)) {
427
+ continue;
428
+ }
429
+
426
430
  for (let i = 0; i < spec.axesSpec.length; ++i) {
427
431
  const qAx = spec.axesSpec[i];
428
432
  const tAx = oth.axesSpec[i];
@@ -435,6 +439,9 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
435
439
  if (!matchDomain(qAx.domain, tAx.domain)) {
436
440
  continue out;
437
441
  }
442
+ if (!matchDomain(qAx.contextDomain, tAx.contextDomain)) {
443
+ continue out;
444
+ }
438
445
  }
439
446
 
440
447
  result.push(data.obj);
@@ -457,7 +464,8 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
457
464
  spec.axesSpec.length === 1 &&
458
465
  spec.axesSpec[0].name === axis.name &&
459
466
  spec.axesSpec[0].type === axis.type &&
460
- matchDomain(axis.domain, spec.axesSpec[0].domain)
467
+ matchDomain(axis.domain, spec.axesSpec[0].domain) &&
468
+ matchDomain(axis.contextDomain, spec.axesSpec[0].contextDomain)
461
469
  ) {
462
470
  if (column.obj.data.resourceType.name !== "PColumnData/Json") {
463
471
  throw Error(`Expected JSON column for labels, got: ${column.obj.data.resourceType.name}`);
@@ -149,19 +149,25 @@ function fallbackIdDeriver(originalId: PObjectId, axisFilters?: AxisFilterByIdx[
149
149
  function hasAnchors(selector: unknown): selector is AnchoredPColumnSelector {
150
150
  if (!selector || typeof selector !== "object") return false;
151
151
  const potentialAnchored = selector as Record<string, any>;
152
- const domainHasAnchors =
153
- potentialAnchored["domain"] &&
154
- typeof potentialAnchored["domain"] === "object" &&
155
- Object.values(potentialAnchored["domain"]).some(
156
- (v: unknown) => typeof v === "object" && v !== null && "anchor" in v,
157
- );
152
+ const hasAnchorValues = (obj: unknown) =>
153
+ obj &&
154
+ typeof obj === "object" &&
155
+ Object.values(obj).some((v: unknown) => typeof v === "object" && v !== null && "anchor" in v);
156
+ const domainHasAnchors = hasAnchorValues(potentialAnchored["domain"]);
157
+ const contextDomainHasAnchors = hasAnchorValues(potentialAnchored["contextDomain"]);
158
158
  const axesHaveAnchors =
159
159
  potentialAnchored["axes"] &&
160
160
  Array.isArray(potentialAnchored["axes"]) &&
161
161
  potentialAnchored["axes"].some(
162
162
  (a: unknown) => typeof a === "object" && a !== null && "anchor" in a,
163
163
  );
164
- return !!potentialAnchored["domainAnchor"] || domainHasAnchors || axesHaveAnchors;
164
+ return (
165
+ !!potentialAnchored["domainAnchor"] ||
166
+ !!potentialAnchored["contextDomainAnchor"] ||
167
+ domainHasAnchors ||
168
+ contextDomainHasAnchors ||
169
+ axesHaveAnchors
170
+ );
165
171
  }
166
172
 
167
173
  /**