@platforma-sdk/model 1.34.10 → 1.37.2

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/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PlatformaSDKVersion = "1.34.10";
1
+ export declare const PlatformaSDKVersion = "1.37.2";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,YAAY,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.34.10",
3
+ "version": "1.37.2",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -21,8 +21,8 @@
21
21
  "utility-types": "^3.11.0",
22
22
  "canonicalize": "~2.1.0",
23
23
  "zod": "~3.23.8",
24
- "@milaboratories/pl-model-common": "^1.15.5",
25
- "@milaboratories/pl-error-like": "^1.12.1"
24
+ "@milaboratories/pl-model-common": "^1.15.7",
25
+ "@milaboratories/pl-error-like": "^1.12.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "~5.5.4",
@@ -31,7 +31,7 @@
31
31
  "jest": "^29.7.0",
32
32
  "@jest/globals": "^29.7.0",
33
33
  "ts-jest": "^29.2.6",
34
- "@milaboratories/platforma-build-configs": "1.0.3",
34
+ "@milaboratories/build-configs": "1.0.4",
35
35
  "@platforma-sdk/eslint-config": "1.0.3"
36
36
  },
37
37
  "scripts": {
@@ -3,12 +3,13 @@ import type {
3
3
  AxisSpec,
4
4
  CanonicalizedJson,
5
5
  DataInfo,
6
- JoinEntry,
6
+ ListOptionBase,
7
7
  PColumn,
8
8
  PColumnIdAndSpec,
9
9
  PColumnSpec,
10
10
  PColumnValues,
11
11
  PObjectId,
12
+ PTableColumnId,
12
13
  PTableColumnIdColumn,
13
14
  PTableColumnSpec,
14
15
  PTableDef,
@@ -23,7 +24,6 @@ import {
23
24
  getAxisId,
24
25
  getColumnIdAndSpec,
25
26
  matchAxisId,
26
- parseJson,
27
27
  } from '@milaboratories/pl-model-common';
28
28
  import type {
29
29
  AxisLabelProvider,
@@ -39,38 +39,18 @@ import {
39
39
  /** Canonicalized PTableColumnSpec JSON string */
40
40
  export type PTableColumnSpecJson = CanonicalizedJson<PTableColumnSpec>;
41
41
 
42
- /** Encode `PTableColumnId` as canonicalized JSON string */
43
- export function stringifyPTableColumnSpec(spec: PTableColumnSpec): PTableColumnSpecJson {
44
- const type = spec.type;
45
- switch (type) {
46
- case 'axis':
47
- return canonicalizeJson(spec);
48
- case 'column':
49
- return canonicalizeJson(spec);
50
- default:
51
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
52
- throw Error(`unsupported column type: ${type satisfies never}`);
53
- }
54
- }
55
-
56
- /** Data table state */
57
- export type PlDataTableGridState = {
58
- // TODO request stable key from the driver
59
- /**
60
- * Hash of the specs for now, but in the future it will be a stable id of the source
61
- */
62
- sourceId?: string;
42
+ export type PlDataTableGridStateCore = {
63
43
  /** Includes column ordering */
64
44
  columnOrder?: {
65
45
  /** All colIds in order */
66
- orderedColIds: string[];
46
+ orderedColIds: PTableColumnSpecJson[];
67
47
  };
68
48
  /** Includes current sort columns and direction */
69
49
  sort?: {
70
50
  /** Sorted columns and directions in order */
71
51
  sortModel: {
72
52
  /** Column Id to apply the sort to. */
73
- colId: string;
53
+ colId: PTableColumnSpecJson;
74
54
  /** Sort direction */
75
55
  sort: 'asc' | 'desc';
76
56
  }[];
@@ -80,33 +60,40 @@ export type PlDataTableGridState = {
80
60
  /** All colIds which were hidden */
81
61
  hiddenColIds: PTableColumnSpecJson[];
82
62
  };
83
- /** current sheet selections */
84
- sheets?: Record<string, string | number>;
85
63
  };
86
64
 
87
65
  /** TODO: refactor to use sheets in the grid state */
88
- export type PlDataTableGridStateWithoutSheets = Omit<PlDataTableGridState, 'sheets'>;
66
+ export type PlDataTableGridStateWithoutSheets = PlDataTableGridStateCore & {
67
+ /** DataSource identifier for state management */
68
+ sourceId?: string;
69
+ };
70
+
71
+ /** Data table state */
72
+ export type PlDataTableGridState = PlDataTableGridStateWithoutSheets & {
73
+ /** current sheet selections */
74
+ sheets?: Record<CanonicalizedJson<AxisId>, string | number>;
75
+ };
89
76
 
90
77
  export type PlDataTableSheet = {
91
78
  /** spec of the axis to use */
92
79
  axis: AxisSpec;
93
- /** options to show in the filter tan */
94
- options: {
95
- /** value of the option (should be one of the values in the axis or column) */
96
- value: string | number;
97
- /** corresponding label */
98
- label: string;
99
- }[];
80
+ /** options to show in the filter dropdown */
81
+ options: ListOptionBase<string | number>[];
100
82
  /** default (selected) value */
101
83
  defaultValue?: string | number;
102
84
  };
103
85
 
86
+ export type PlDataTableSheetState = {
87
+ /** id of the axis */
88
+ axisId: AxisId;
89
+ /** selected value */
90
+ value: string | number;
91
+ };
92
+
104
93
  /**
105
94
  * Params used to get p-table handle from the driver
106
95
  */
107
96
  export type PTableParams = {
108
- /** For sourceType: 'pframe' the join is original one, enriched with label columns */
109
- join?: JoinEntry<PColumnIdAndSpec>;
110
97
  sorting?: PTableSorting[];
111
98
  filters?: PTableRecordFilter[];
112
99
  };
@@ -121,6 +108,62 @@ export type PlDataTableState = {
121
108
  pTableParams?: PTableParams;
122
109
  };
123
110
 
111
+ /**
112
+ * PlDataTableV2 persisted state
113
+ */
114
+ export type PlDataTableStateV2 =
115
+ // Old versions of the state
116
+ | PlDataTableState
117
+ // Normalized state
118
+ | PlDataTableStateV2Normalized;
119
+
120
+ export type PlDataTableStateV2CacheEntry = {
121
+ /** DataSource identifier for state management */
122
+ sourceId: string;
123
+ /** Internal ag-grid state */
124
+ gridState: PlDataTableGridStateCore;
125
+ /** Sheets state */
126
+ sheetsState: PlDataTableSheetState[];
127
+ };
128
+
129
+ export type PTableParamsV2 = {
130
+ sorting: PTableSorting[];
131
+ filters: PTableRecordFilter[];
132
+ hiddenColIds: PObjectId[] | null;
133
+ };
134
+
135
+ export type PlDataTableStateV2Normalized = {
136
+ // version for upgrades
137
+ version: 2;
138
+ // internal ag-grid states, LRU cache for 5 sourceId-s
139
+ stateCache: PlDataTableStateV2CacheEntry[];
140
+ // mapping of gridState for current sourceId onto the p-table data structures
141
+ pTableParams: PTableParamsV2;
142
+ };
143
+
144
+ /** Create default PlDataTableStateV2 */
145
+ export function createPlDataTableStateV2(): PlDataTableStateV2Normalized {
146
+ return {
147
+ version: 2,
148
+ stateCache: [],
149
+ pTableParams: {
150
+ sorting: [],
151
+ filters: [],
152
+ hiddenColIds: null,
153
+ },
154
+ };
155
+ }
156
+
157
+ /** Upgrade PlDataTableStateV2 to the latest version */
158
+ export function upgradePlDataTableStateV2(state: PlDataTableStateV2): PlDataTableStateV2Normalized {
159
+ // v1 -> v2
160
+ if (!('version' in state)) {
161
+ // Non upgradeable as sourceId calculation algorithm has changed, resetting state to default
162
+ return createPlDataTableStateV2();
163
+ }
164
+ return state;
165
+ }
166
+
124
167
  /** PlTableFilters filter entry */
125
168
  export type PlTableFilterIsNotNA = {
126
169
  /** Predicate type */
@@ -332,9 +375,12 @@ export type PlTableFiltersModel = {
332
375
  };
333
376
 
334
377
  export type CreatePlDataTableOps = {
335
- /** Table filters, should contain */
378
+ /** Filters for columns and non-partitioned axes */
336
379
  filters?: PTableRecordFilter[];
337
380
 
381
+ /** Sorting to columns hidden from user */
382
+ sorting?: PTableSorting[];
383
+
338
384
  /**
339
385
  * Selects columns for which will be inner-joined to the table.
340
386
  *
@@ -558,8 +604,15 @@ export function createPlDataTable<A, U>(
558
604
 
559
605
  const coreJoinType = ops?.coreJoinType ?? 'full';
560
606
  const filters: PTableRecordSingleValueFilterV2[]
561
- = [...(ops?.filters ?? []), ...(tableState?.pTableParams?.filters ?? [])];
562
- const sorting: PTableSorting[] = tableState?.pTableParams?.sorting ?? [];
607
+ = uniqueBy(
608
+ [...(ops?.filters ?? []), ...(tableState?.pTableParams?.filters ?? [])],
609
+ (f) => canonicalizeJson<PTableColumnId>(f.column),
610
+ );
611
+ const sorting: PTableSorting[]
612
+ = uniqueBy(
613
+ [...(ops?.sorting ?? []), ...(tableState?.pTableParams?.sorting ?? [])],
614
+ (s) => canonicalizeJson<PTableColumnId>(s.column),
615
+ );
563
616
 
564
617
  const allLabelColumns = getAllLabelColumns(ctx.resultPool);
565
618
  if (!allLabelColumns) return undefined;
@@ -575,10 +628,10 @@ export function createPlDataTable<A, U>(
575
628
 
576
629
  /** PlAgDataTable model */
577
630
  export type PlDataTableModel = {
578
- /** p-table specification (full, including hidden columns) */
579
- tableSpec: PTableColumnSpec[];
580
- /** p-table handle (integration of visible columns data) */
581
- tableHandle: PTableHandle;
631
+ /** p-table including all columns, used to show the full specification of the table */
632
+ fullTableHandle: PTableHandle;
633
+ /** p-table including only visible columns, used to get the data */
634
+ visibleTableHandle: PTableHandle;
582
635
  };
583
636
 
584
637
  /**
@@ -597,6 +650,14 @@ export function isColumnOptional(spec: { annotations?: Record<string, string> })
597
650
  return spec.annotations?.['pl7.app/table/visibility'] === 'optional';
598
651
  }
599
652
 
653
+ /**
654
+ * Return unique entries of the array by the provided id
655
+ * For each id, the last entry is kept
656
+ */
657
+ export function uniqueBy<T>(array: T[], makeId: (entry: T) => string): T[] {
658
+ return [...new Map(array.map((e) => [makeId(e), e])).values()];
659
+ }
660
+
600
661
  /**
601
662
  * Create p-table spec and handle given ui table state
602
663
  *
@@ -608,30 +669,36 @@ export function isColumnOptional(spec: { annotations?: Record<string, string> })
608
669
  export function createPlDataTableV2<A, U>(
609
670
  ctx: RenderCtx<A, U>,
610
671
  inputColumns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],
611
- mainColumnPredicate: (spec: PColumnSpec) => boolean,
612
- tableState: PlDataTableState | undefined,
672
+ tableState: PlDataTableStateV2 | undefined,
613
673
  ops?: CreatePlDataTableOps,
614
674
  ): PlDataTableModel | undefined {
675
+ const tableStateNormalized = upgradePlDataTableStateV2(tableState ?? createPlDataTableStateV2());
676
+
615
677
  const coreJoinType = ops?.coreJoinType ?? 'full';
616
678
  const filters: PTableRecordSingleValueFilterV2[]
617
- = [...(ops?.filters ?? []), ...(tableState?.pTableParams?.filters ?? [])];
618
- const sorting: PTableSorting[] = tableState?.pTableParams?.sorting ?? [];
679
+ = uniqueBy(
680
+ [...(ops?.filters ?? []), ...tableStateNormalized.pTableParams.filters],
681
+ (f) => canonicalizeJson<PTableColumnId>(f.column),
682
+ );
683
+ const sorting: PTableSorting[]
684
+ = uniqueBy(
685
+ [...(ops?.sorting ?? []), ...tableStateNormalized.pTableParams.sorting],
686
+ (s) => canonicalizeJson<PTableColumnId>(s.column),
687
+ );
619
688
  const columns = inputColumns.filter((c) => !isColumnHidden(c.spec));
620
689
 
621
- const mainColumn = columns.find((c) => mainColumnPredicate(c.spec));
622
- if (!mainColumn) return undefined;
623
-
624
690
  const allLabelColumns = getAllLabelColumns(ctx.resultPool);
625
691
  if (!allLabelColumns) return undefined;
626
692
 
693
+ const fullLabelColumns = getMatchingLabelColumns(columns.map(getColumnIdAndSpec), allLabelColumns);
694
+ const fullDef = createPTableDef(columns, fullLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);
695
+ const fullHandle = ctx.createPTable(fullDef);
696
+
627
697
  const hiddenColumns = new Set<PObjectId>(((): PObjectId[] => {
628
698
  // Inner join works as a filter - all columns must be present
629
699
  if (coreJoinType === 'inner') return [];
630
700
 
631
- const hiddenColIds = tableState?.gridState.columnVisibility?.hiddenColIds
632
- ?.map(parseJson)
633
- .filter((c) => c.type === 'column')
634
- .map((c) => c.id);
701
+ const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;
635
702
  if (hiddenColIds) return hiddenColIds;
636
703
 
637
704
  return columns
@@ -639,38 +706,29 @@ export function createPlDataTableV2<A, U>(
639
706
  .map((c) => c.id);
640
707
  })());
641
708
 
642
- // Main column must always be included in join to integrate all other columns
643
- hiddenColumns.delete(mainColumn.id);
709
+ // Preserve core columns as they change the shape of join.
710
+ if (ops?.coreColumnPredicate) {
711
+ const coreColumns = columns.flatMap((c) => ops?.coreColumnPredicate?.(c.spec) ? [c.id] : []);
712
+ coreColumns.forEach((c) => hiddenColumns.delete(c));
713
+ }
714
+
644
715
  // Filters decrease the number of result rows, sorting changes the order of result rows
645
716
  [...filters.map((f) => f.column), ...sorting.map((s) => s.column)]
646
717
  .filter((c): c is PTableColumnIdColumn => c.type === 'column')
647
718
  .map((c) => hiddenColumns.delete(c.id));
648
719
 
649
720
  const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));
650
- const labelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);
651
-
652
- const spec: PTableColumnSpec[] = [
653
- ...mainColumn.spec.axesSpec.map((axis) => ({
654
- type: 'axis',
655
- id: getAxisId(axis),
656
- spec: axis,
657
- } satisfies PTableColumnSpec)),
658
- ...[...columns, ...labelColumns].map((c) => ({
659
- type: 'column',
660
- id: c.id,
661
- spec: c.spec,
662
- } satisfies PTableColumnSpec)),
663
- ];
721
+ const visibleLabelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);
664
722
 
665
723
  // if at least one column is not yet computed, we can't show the table
666
- if (!allColumnsComputed([...visibleColumns, ...labelColumns])) return undefined;
724
+ if (!allColumnsComputed([...visibleColumns, ...visibleLabelColumns])) return undefined;
667
725
 
668
- const handle = ctx.createPTable(
669
- createPTableDef(columns, labelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate));
726
+ const visibleDef = createPTableDef(visibleColumns, visibleLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);
727
+ const visibleHandle = ctx.createPTable(visibleDef);
670
728
 
671
729
  return {
672
- tableSpec: spec,
673
- tableHandle: handle,
730
+ fullTableHandle: fullHandle,
731
+ visibleTableHandle: visibleHandle,
674
732
  } satisfies PlDataTableModel;
675
733
  }
676
734