@finos/legend-data-cube 0.0.3 → 0.0.5

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 (108) hide show
  1. package/lib/components/editor/DataCubeEditorColumnPropertiesPanel.d.ts.map +1 -1
  2. package/lib/components/editor/DataCubeEditorColumnPropertiesPanel.js +7 -4
  3. package/lib/components/editor/DataCubeEditorColumnPropertiesPanel.js.map +1 -1
  4. package/lib/components/editor/DataCubeEditorGeneralPropertiesPanel.d.ts.map +1 -1
  5. package/lib/components/editor/DataCubeEditorGeneralPropertiesPanel.js +10 -15
  6. package/lib/components/editor/DataCubeEditorGeneralPropertiesPanel.js.map +1 -1
  7. package/lib/components/editor/DataCubeEditorSortsPanel.d.ts.map +1 -1
  8. package/lib/components/editor/DataCubeEditorSortsPanel.js +9 -9
  9. package/lib/components/editor/DataCubeEditorSortsPanel.js.map +1 -1
  10. package/lib/index.css +1 -1
  11. package/lib/package.json +1 -1
  12. package/lib/stores/core/DataCubeConfiguration.d.ts +13 -7
  13. package/lib/stores/core/DataCubeConfiguration.d.ts.map +1 -1
  14. package/lib/stores/core/DataCubeConfiguration.js +25 -15
  15. package/lib/stores/core/DataCubeConfiguration.js.map +1 -1
  16. package/lib/stores/core/DataCubeConfigurationBuilder.d.ts.map +1 -1
  17. package/lib/stores/core/DataCubeConfigurationBuilder.js +3 -2
  18. package/lib/stores/core/DataCubeConfigurationBuilder.js.map +1 -1
  19. package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
  20. package/lib/stores/core/DataCubeQueryBuilder.js +23 -17
  21. package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
  22. package/lib/stores/core/DataCubeQueryBuilderUtils.js +2 -2
  23. package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
  24. package/lib/stores/core/DataCubeQueryEngine.d.ts +19 -11
  25. package/lib/stores/core/DataCubeQueryEngine.d.ts.map +1 -1
  26. package/lib/stores/core/DataCubeQueryEngine.js +21 -14
  27. package/lib/stores/core/DataCubeQueryEngine.js.map +1 -1
  28. package/lib/stores/core/DataCubeQuerySnapshot.d.ts +1 -1
  29. package/lib/stores/core/DataCubeQuerySnapshotBuilder.d.ts.map +1 -1
  30. package/lib/stores/core/DataCubeQuerySnapshotBuilder.js +131 -80
  31. package/lib/stores/core/DataCubeQuerySnapshotBuilder.js.map +1 -1
  32. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.d.ts +6 -7
  33. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.d.ts.map +1 -1
  34. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js +27 -91
  35. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js.map +1 -1
  36. package/lib/stores/core/DataCubeQuerySnapshotManager.js +1 -1
  37. package/lib/stores/core/DataCubeQuerySnapshotManager.js.map +1 -1
  38. package/lib/stores/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts +1 -2
  39. package/lib/stores/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts.map +1 -1
  40. package/lib/stores/editor/DataCubeEditorGeneralPropertiesPanelState.js +4 -6
  41. package/lib/stores/editor/DataCubeEditorGeneralPropertiesPanelState.js.map +1 -1
  42. package/lib/stores/editor/DataCubeEditorMutableConfiguration.d.ts +15 -8
  43. package/lib/stores/editor/DataCubeEditorMutableConfiguration.d.ts.map +1 -1
  44. package/lib/stores/editor/DataCubeEditorMutableConfiguration.js +50 -26
  45. package/lib/stores/editor/DataCubeEditorMutableConfiguration.js.map +1 -1
  46. package/lib/stores/editor/DataCubeEditorPivotLayoutPanelState.d.ts +30 -0
  47. package/lib/stores/editor/DataCubeEditorPivotLayoutPanelState.d.ts.map +1 -0
  48. package/lib/stores/editor/DataCubeEditorPivotLayoutPanelState.js +43 -0
  49. package/lib/stores/editor/DataCubeEditorPivotLayoutPanelState.js.map +1 -0
  50. package/lib/stores/editor/DataCubeEditorSortsPanelState.d.ts +3 -3
  51. package/lib/stores/editor/DataCubeEditorSortsPanelState.d.ts.map +1 -1
  52. package/lib/stores/editor/DataCubeEditorSortsPanelState.js +11 -11
  53. package/lib/stores/editor/DataCubeEditorSortsPanelState.js.map +1 -1
  54. package/lib/stores/editor/DataCubeEditorState.d.ts +2 -0
  55. package/lib/stores/editor/DataCubeEditorState.d.ts.map +1 -1
  56. package/lib/stores/editor/DataCubeEditorState.js +5 -0
  57. package/lib/stores/editor/DataCubeEditorState.js.map +1 -1
  58. package/lib/stores/extend/DataCubeExtendManagerState.js +1 -1
  59. package/lib/stores/extend/DataCubeExtendManagerState.js.map +1 -1
  60. package/lib/stores/grid/DataCubeGridClientEngine.d.ts.map +1 -1
  61. package/lib/stores/grid/DataCubeGridClientEngine.js +41 -36
  62. package/lib/stores/grid/DataCubeGridClientEngine.js.map +1 -1
  63. package/lib/stores/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
  64. package/lib/stores/grid/DataCubeGridConfigurationBuilder.js +39 -3
  65. package/lib/stores/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
  66. package/lib/stores/grid/DataCubeGridControllerState.d.ts +6 -3
  67. package/lib/stores/grid/DataCubeGridControllerState.d.ts.map +1 -1
  68. package/lib/stores/grid/DataCubeGridControllerState.js +35 -17
  69. package/lib/stores/grid/DataCubeGridControllerState.js.map +1 -1
  70. package/lib/stores/grid/DataCubeGridMenuBuilder.d.ts.map +1 -1
  71. package/lib/stores/grid/DataCubeGridMenuBuilder.js +52 -31
  72. package/lib/stores/grid/DataCubeGridMenuBuilder.js.map +1 -1
  73. package/lib/stores/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
  74. package/lib/stores/grid/DataCubeGridQueryBuilder.js +3 -3
  75. package/lib/stores/grid/DataCubeGridQueryBuilder.js.map +1 -1
  76. package/lib/stores/grid/DataCubeGridQuerySnapshotBuilder.d.ts.map +1 -1
  77. package/lib/stores/grid/DataCubeGridQuerySnapshotBuilder.js +14 -7
  78. package/lib/stores/grid/DataCubeGridQuerySnapshotBuilder.js.map +1 -1
  79. package/lib/stores/grid/DataCubeGridState.d.ts.map +1 -1
  80. package/lib/stores/grid/DataCubeGridState.js +9 -5
  81. package/lib/stores/grid/DataCubeGridState.js.map +1 -1
  82. package/package.json +3 -3
  83. package/src/components/editor/DataCubeEditorColumnPropertiesPanel.tsx +11 -5
  84. package/src/components/editor/DataCubeEditorGeneralPropertiesPanel.tsx +94 -101
  85. package/src/components/editor/DataCubeEditorSortsPanel.tsx +12 -10
  86. package/src/stores/core/DataCubeConfiguration.ts +33 -15
  87. package/src/stores/core/DataCubeConfigurationBuilder.ts +3 -2
  88. package/src/stores/core/DataCubeQueryBuilder.ts +33 -20
  89. package/src/stores/core/DataCubeQueryBuilderUtils.ts +2 -2
  90. package/src/stores/core/DataCubeQueryEngine.ts +22 -12
  91. package/src/stores/core/DataCubeQuerySnapshot.ts +1 -1
  92. package/src/stores/core/DataCubeQuerySnapshotBuilder.ts +135 -120
  93. package/src/stores/core/DataCubeQuerySnapshotBuilderUtils.ts +33 -107
  94. package/src/stores/core/DataCubeQuerySnapshotManager.ts +1 -1
  95. package/src/stores/editor/DataCubeEditorGeneralPropertiesPanelState.ts +6 -9
  96. package/src/stores/editor/DataCubeEditorMutableConfiguration.ts +68 -28
  97. package/src/stores/editor/DataCubeEditorPivotLayoutPanelState.ts +71 -0
  98. package/src/stores/editor/DataCubeEditorSortsPanelState.ts +11 -11
  99. package/src/stores/editor/DataCubeEditorState.tsx +5 -0
  100. package/src/stores/extend/DataCubeExtendManagerState.tsx +1 -1
  101. package/src/stores/grid/DataCubeGridClientEngine.ts +52 -48
  102. package/src/stores/grid/DataCubeGridConfigurationBuilder.tsx +45 -4
  103. package/src/stores/grid/DataCubeGridControllerState.ts +44 -20
  104. package/src/stores/grid/DataCubeGridMenuBuilder.tsx +81 -52
  105. package/src/stores/grid/DataCubeGridQueryBuilder.ts +3 -7
  106. package/src/stores/grid/DataCubeGridQuerySnapshotBuilder.ts +20 -7
  107. package/src/stores/grid/DataCubeGridState.ts +9 -5
  108. package/tsconfig.json +1 -0
@@ -80,6 +80,7 @@ export type DataCubeQueryFunctionMap = {
80
80
  pivot?: V1_AppliedFunction | undefined;
81
81
  pivotCast?: V1_AppliedFunction | undefined;
82
82
  groupBy?: V1_AppliedFunction | undefined;
83
+ groupBySort?: V1_AppliedFunction | undefined;
83
84
  groupExtend?: V1_AppliedFunction | undefined;
84
85
  select?: V1_AppliedFunction | undefined;
85
86
  sort?: V1_AppliedFunction | undefined;
@@ -96,14 +97,6 @@ export enum DataCubeNumberScale {
96
97
  AUTO = 'Auto (k/m/b/t)',
97
98
  }
98
99
 
99
- export enum DataCubeSelectionStat {
100
- COUNT = 'Count',
101
- SUM = 'Sum',
102
- MIN = 'Min',
103
- MAX = 'Max',
104
- AVERAGE = 'Average',
105
- }
106
-
107
100
  export enum DataCubeFont {
108
101
  // sans-serif
109
102
  ARIAL = 'Arial',
@@ -190,6 +183,19 @@ export enum DataCubeAggregateOperator {
190
183
  // custom
191
184
  }
192
185
 
186
+ export enum DataCubeClientSideAggregateOperator {
187
+ SUM = 'sum',
188
+ AVERAGE = 'avg',
189
+ MEDIAN = 'median',
190
+ COUNT = 'count',
191
+ MIN = 'min',
192
+ MAX = 'max',
193
+ VARIANCE_POPULATION = 'var',
194
+ VARIANCE_SAMPLE = 'var_sample',
195
+ STANDARD_DEVIATION_POPULATION = 'std',
196
+ STANDARD_DEVIATION_SAMPLE = 'std_sample',
197
+ }
198
+
193
199
  export enum DataCubeQueryFilterOperator {
194
200
  LESS_THAN = '<', // DONE
195
201
  LESS_THAN_OR_EQUAL = '<=', // DONE
@@ -232,9 +238,9 @@ export enum DataCubeQueryFilterGroupOperator {
232
238
  OR = 'or',
233
239
  }
234
240
 
235
- export enum DataCubeQuerySortOperator {
236
- ASCENDING = 'ascending',
237
- DESCENDING = 'descending',
241
+ export enum DataCubeQuerySortDirection {
242
+ ASCENDING = 'Ascending',
243
+ DESCENDING = 'Descending',
238
244
  }
239
245
 
240
246
  export enum DataCubeColumnPinPlacement {
@@ -281,6 +287,7 @@ export function ofDataType(
281
287
  }
282
288
 
283
289
  export const PIVOT_COLUMN_NAME_VALUE_SEPARATOR = '__|__';
290
+
284
291
  export function isPivotResultColumnName(columnName: string) {
285
292
  return columnName.includes(PIVOT_COLUMN_NAME_VALUE_SEPARATOR);
286
293
  }
@@ -296,10 +303,13 @@ export function getPivotResultColumnBaseColumnName(columnName: string) {
296
303
  );
297
304
  }
298
305
 
306
+ export const TREE_COLUMN_VALUE_SEPARATOR = '__/__';
299
307
  export const DEFAULT_LAMBDA_VARIABLE_NAME = 'x';
300
308
 
301
309
  export const DEFAULT_REPORT_NAME = 'New Report';
302
- export const DEFAULT_ROW_BUFFER = 20;
310
+ export const DEFAULT_TREE_COLUMN_SORT_DIRECTION =
311
+ DataCubeQuerySortDirection.ASCENDING;
312
+ export const DEFAULT_PIVOT_STATISTIC_COLUMN_NAME = 'Total';
303
313
 
304
314
  export const DEFAULT_URL_LABEL_QUERY_PARAM = 'dataCube.linkLabel';
305
315
  export const DEFAULT_MISSING_VALUE_DISPLAY_TEXT = '';
@@ -58,7 +58,7 @@ export type DataCubeQuerySnapshotSimpleExtendedColumn =
58
58
  };
59
59
 
60
60
  export type DataCubeQuerySnapshotSortColumn = DataCubeQuerySnapshotColumn & {
61
- operation: string;
61
+ direction: string;
62
62
  };
63
63
 
64
64
  export type DataCubeQuerySnapshotGroupBy = {
@@ -40,7 +40,7 @@ import {
40
40
  } from './DataCubeQuerySnapshot.js';
41
41
  import { assertType, guaranteeNonNullable } from '@finos/legend-shared';
42
42
  import {
43
- DataCubeQuerySortOperator,
43
+ DataCubeQuerySortDirection,
44
44
  DataCubeFunction,
45
45
  type DataCubeQueryFunctionMap,
46
46
  } from './DataCubeQueryEngine.js';
@@ -83,57 +83,124 @@ type FunctionSequenceCompositionGroupNodePattern =
83
83
  funcs: FunctionSequenceCompositionSimpleNodePattern[];
84
84
  };
85
85
 
86
- // NOTE: this corresponds to the sequence:
87
- // extend()->filter()->select()->sort()->pivot()->cast()->groupBy()->extend()->sort()->limit()
88
- // which represents the ONLY query shape that we currently support
86
+ enum _FUNCTION_SEQUENCE_COMPOSITION_PART {
87
+ LEAF_EXTEND = 'leaf_extend',
88
+ FILTER = 'filter',
89
+ SELECT = 'select',
90
+ PIVOT__GROUP = 'pivot__group',
91
+ PIVOT_SORT = 'pivot_sort',
92
+ PIVOT = 'pivot',
93
+ PIVOT_CAST = 'pivot_cast',
94
+ GROUP_BY__GROUP = 'group_by__group',
95
+ GROUP_BY = 'group_by',
96
+ GROUP_BY_SORT = 'group_by_sort',
97
+ GROUP_EXTEND = 'group_extend',
98
+ SORT = 'sort',
99
+ LIMIT = 'limit',
100
+ }
101
+
102
+ // This corresponds to the function sequence that we currently support:
103
+ //
104
+ // -> extend()
105
+ // ->filter()
106
+ // ->select()
107
+ // ->sort()->pivot()->cast()
108
+ // ->groupBy()->sort()
109
+ // ->extend()
110
+ // ->sort()
111
+ // ->limit()
112
+ //
89
113
  const _FUNCTION_SEQUENCE_COMPOSITION_PATTERN: (
90
114
  | FunctionSequenceCompositionSimpleNodePattern
91
115
  | FunctionSequenceCompositionGroupNodePattern
92
116
  )[] = [
93
- { name: 'leaf_extend', func: DataCubeFunction.EXTEND }, // leaf-level extend
94
- { name: 'filter', func: DataCubeFunction.FILTER },
95
- { name: 'select', func: DataCubeFunction.SELECT },
96
117
  {
97
- name: 'pivot_group',
118
+ // leaf-level extend
119
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.LEAF_EXTEND,
120
+ func: DataCubeFunction.EXTEND,
121
+ },
122
+ {
123
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.FILTER,
124
+ func: DataCubeFunction.FILTER,
125
+ },
126
+ {
127
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.SELECT,
128
+ func: DataCubeFunction.SELECT,
129
+ },
130
+ {
131
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT__GROUP,
132
+ funcs: [
133
+ {
134
+ // sort to ensure stable column ordering
135
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT_SORT,
136
+ func: DataCubeFunction.SORT,
137
+ required: true,
138
+ },
139
+ {
140
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT,
141
+ func: DataCubeFunction.PIVOT,
142
+ required: true,
143
+ },
144
+ {
145
+ // cast to a relation type post pivot() to enable type-checking
146
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT_CAST,
147
+ func: DataCubeFunction.CAST,
148
+ required: true,
149
+ },
150
+ ],
151
+ },
152
+ {
153
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_BY__GROUP,
98
154
  funcs: [
99
- { name: 'pivot_sort', func: DataCubeFunction.SORT, required: true }, // pre-pivot sort
100
- { name: 'pivot', func: DataCubeFunction.PIVOT, required: true },
101
- { name: 'pivot_cast', func: DataCubeFunction.CAST, required: true }, // cast to a relation type post pivot() to enable type-checking
155
+ {
156
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_BY,
157
+ func: DataCubeFunction.GROUP_BY,
158
+ required: true,
159
+ },
160
+ {
161
+ // sort to ensure stable row ordering
162
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_BY_SORT,
163
+ func: DataCubeFunction.SORT,
164
+ required: true,
165
+ },
102
166
  ],
103
167
  },
104
- { name: 'group_by', func: DataCubeFunction.GROUP_BY },
105
- { name: 'group_extend', func: DataCubeFunction.EXTEND }, // group-level extend
106
- { name: 'sort', func: DataCubeFunction.SORT },
107
- { name: 'limit', func: DataCubeFunction.LIMIT },
168
+ {
169
+ // group-level extend
170
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_EXTEND,
171
+ func: DataCubeFunction.EXTEND,
172
+ },
173
+ {
174
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.SORT,
175
+ func: DataCubeFunction.SORT,
176
+ },
177
+ {
178
+ name: _FUNCTION_SEQUENCE_COMPOSITION_PART.LIMIT,
179
+ func: DataCubeFunction.LIMIT,
180
+ },
108
181
  ];
109
182
  const _FUNCTION_SEQUENCE_COMPOSITION_PATTERN_REGEXP = new RegExp(
110
183
  `^${_FUNCTION_SEQUENCE_COMPOSITION_PATTERN
111
184
  .map((node) =>
112
185
  'funcs' in node
113
- ? `(${node.funcs.map(
114
- (childNode) =>
115
- `(?<${childNode.name}><${_name(childNode.func)}>)${childNode.repeat ? '*' : !childNode.required ? '?' : ''}`,
116
- )})${node.repeat ? '*' : !node.required ? '?' : ''}`
117
- : `(?<${node.name}><${_name(node.func)}>)${node.repeat ? '*' : !node.required ? '?' : ''}`,
186
+ ? `(${node.funcs
187
+ .map(
188
+ (childNode) =>
189
+ `(?<${childNode.name}><${_name(childNode.func)}>____\\d+)${childNode.repeat ? '*' : !childNode.required ? '?' : ''}`,
190
+ )
191
+ .join('')})${node.repeat ? '*' : !node.required ? '?' : ''}`
192
+ : `(?<${node.name}><${_name(node.func)}>____\\d+)${node.repeat ? '*' : !node.required ? '?' : ''}`,
118
193
  )
119
194
  .join('')}$`,
120
195
  );
121
196
 
122
- type FunctionSequenceMatchingResult = {
123
- sequence: V1_AppliedFunction[];
124
- leafExtend: boolean;
125
- pivot: boolean;
126
- groupExtend: boolean;
127
- sort: boolean;
128
- };
129
197
  /**
130
- * Since the query created by DataCube will be a chain call of various functions,
131
- * this utility function will extract that sequence of function calls as well as
132
- * do various basic checks for the validity, composition, and order of those functions.
198
+ * Turn the function sequence into a map of available functions
199
+ * for easier construction of the snapshot
133
200
  */
134
- function extractQueryFunctionSequence(
201
+ function extractFunctionMap(
135
202
  query: V1_ValueSpecification,
136
- ): FunctionSequenceMatchingResult {
203
+ ): DataCubeQueryFunctionMap {
137
204
  // Make sure this is a sequence of function calls
138
205
  if (!(query instanceof V1_AppliedFunction)) {
139
206
  throw new Error(
@@ -169,7 +236,7 @@ function extractQueryFunctionSequence(
169
236
 
170
237
  // Check that sequence follows the supported pattern
171
238
  const sequenceFormText = sequence
172
- .map((func) => `<${_name(func.function)}>`)
239
+ .map((func, idx) => `<${_name(func.function)}>____${idx}`)
173
240
  .join('');
174
241
  const matchResult = sequenceFormText.match(
175
242
  _FUNCTION_SEQUENCE_COMPOSITION_PATTERN_REGEXP,
@@ -180,83 +247,30 @@ function extractQueryFunctionSequence(
180
247
  );
181
248
  }
182
249
 
183
- return {
184
- sequence,
185
- leafExtend: Boolean(matchResult.groups?.leaf_extend),
186
- pivot: Boolean(matchResult.groups?.pivot),
187
- groupExtend: Boolean(matchResult.groups?.group_extend),
188
- sort: Boolean(matchResult.groups?.sort),
250
+ const _process = (key: string): V1_AppliedFunction | undefined => {
251
+ const match = matchResult.groups?.[key];
252
+ if (!match || match.indexOf('____') === -1) {
253
+ return undefined;
254
+ }
255
+ const idx = Number(match.split('____')[1]);
256
+ if (isNaN(idx) || idx >= sequence.length) {
257
+ return undefined;
258
+ }
259
+ return sequence[idx];
189
260
  };
190
- }
191
-
192
- /**
193
- * Turn the function sequence into a map of available functions
194
- * for easier construction of the snapshot
195
- */
196
- function extractFunctionMap(
197
- sequenceMatchingResult: FunctionSequenceMatchingResult,
198
- ): DataCubeQueryFunctionMap {
199
- const {
200
- sequence,
201
- leafExtend: hasLeafExtend,
202
- groupExtend: hasGroupExtend,
203
- pivot: hasPivot,
204
- sort: hasSort,
205
- } = sequenceMatchingResult;
206
- const leafExtend = hasLeafExtend
207
- ? sequence.find((func) =>
208
- matchFunctionName(func.function, DataCubeFunction.EXTEND),
209
- )
210
- : undefined;
211
- const filter = sequence.find((func) =>
212
- matchFunctionName(func.function, DataCubeFunction.FILTER),
213
- );
214
- const select = sequence.find((func) =>
215
- matchFunctionName(func.function, DataCubeFunction.SELECT),
216
- );
217
- const pivotSort = hasPivot
218
- ? sequence.find((func) =>
219
- matchFunctionName(func.function, DataCubeFunction.SORT),
220
- )
221
- : undefined;
222
- const pivot = hasPivot
223
- ? sequence.find((func) =>
224
- matchFunctionName(func.function, DataCubeFunction.PIVOT),
225
- )
226
- : undefined;
227
- const pivotCast = hasPivot
228
- ? sequence.find((func) =>
229
- matchFunctionName(func.function, DataCubeFunction.CAST),
230
- )
231
- : undefined;
232
- const groupBy = sequence.find((func) =>
233
- matchFunctionName(func.function, DataCubeFunction.GROUP_BY),
234
- );
235
- const groupExtend = hasGroupExtend
236
- ? sequence.find((func) =>
237
- matchFunctionName(func.function, DataCubeFunction.EXTEND),
238
- )
239
- : undefined;
240
- const sort = hasSort
241
- ? sequence.find((func) =>
242
- matchFunctionName(func.function, DataCubeFunction.SORT),
243
- )
244
- : undefined;
245
- const limit = sequence.find((func) =>
246
- matchFunctionName(func.function, DataCubeFunction.LIMIT),
247
- );
248
261
 
249
262
  return {
250
- leafExtend: leafExtend,
251
- select,
252
- filter,
253
- groupBy,
254
- pivotSort,
255
- pivot,
256
- pivotCast,
257
- groupExtend,
258
- sort,
259
- limit,
263
+ leafExtend: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.LEAF_EXTEND),
264
+ select: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.SELECT),
265
+ filter: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.FILTER),
266
+ pivotSort: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT_SORT),
267
+ pivot: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT_CAST),
268
+ pivotCast: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.PIVOT_CAST),
269
+ groupBy: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_BY),
270
+ groupBySort: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_BY_SORT),
271
+ groupExtend: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.GROUP_EXTEND),
272
+ sort: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.SORT),
273
+ limit: _process(_FUNCTION_SEQUENCE_COMPOSITION_PART.LIMIT),
260
274
  };
261
275
  }
262
276
 
@@ -277,8 +291,7 @@ export function validateAndBuildQuerySnapshot(
277
291
  // Build the function call sequence and the function map to make the
278
292
  // analysis more ergonomic
279
293
 
280
- const sequenceMatchingResult = extractQueryFunctionSequence(partialQuery);
281
- const funcMap = extractFunctionMap(sequenceMatchingResult);
294
+ const funcMap = extractFunctionMap(partialQuery);
282
295
  const snapshot = DataCubeQuerySnapshot.create(
283
296
  baseQuery.name,
284
297
  baseQuery.source.runtime,
@@ -321,7 +334,7 @@ export function validateAndBuildQuerySnapshot(
321
334
 
322
335
  // --------------------------------- PIVOT ---------------------------------
323
336
  /** TODO: @datacube roundtrip */
324
- // TODO: verify group-by agg columns, pivot agg columns and configuration agree
337
+ // TODO: verify groupBy agg columns, pivot agg columns and configuration agree
325
338
 
326
339
  // --------------------------------- GROUP BY ---------------------------------
327
340
 
@@ -330,7 +343,8 @@ export function validateAndBuildQuerySnapshot(
330
343
  columns: _colSpecArrayParam(funcMap.groupBy, 0).colSpecs.map((colSpec) =>
331
344
  _col(colSpec),
332
345
  ),
333
- // TODO: verify group-by agg columns, pivot agg columns and configuration agree
346
+ // TODO: verify groupBy agg columns, pivot agg columns and configuration agree
347
+ // TODO: verify groupBy sort columns and configuration agree
334
348
  };
335
349
  }
336
350
 
@@ -348,10 +362,10 @@ export function validateAndBuildQuerySnapshot(
348
362
  ]);
349
363
  return {
350
364
  ..._col(_colSpecParam(sortColFunc, 0)),
351
- operation:
365
+ direction:
352
366
  _name(sortColFunc.function) === DataCubeFunction.ASC
353
- ? DataCubeQuerySortOperator.ASCENDING
354
- : DataCubeQuerySortOperator.DESCENDING,
367
+ ? DataCubeQuerySortDirection.ASCENDING
368
+ : DataCubeQuerySortDirection.DESCENDING,
355
369
  };
356
370
  },
357
371
  );
@@ -394,12 +408,13 @@ export function validateAndBuildQuerySnapshot(
394
408
  DataCubeConfiguration.serialization.toJson(configuration);
395
409
  /**
396
410
  * TODO: @datacube roundtrip - implement the logic to reconcile the configuration with the query
397
- * - columns (missing/extra columns - remove or generate default column configuration)
398
- * - column kind
399
- * - column type
400
- * - base off the type, check the settings
401
- * - aggregation
402
- * - verify group-by agg columns, pivot agg columns and configuration agree
411
+ * - [ ] columns (missing/extra columns - remove or generate default column configuration)
412
+ * - [ ] column kind
413
+ * - [ ] column type
414
+ * - [ ] base off the type, check the settings
415
+ * - [ ] aggregation
416
+ * - [ ] verify groupBy agg columns, pivot agg columns and configuration agree
417
+ * - [ ] verify groupBy sort columns and tree column sort direction configuration agree
403
418
  */
404
419
 
405
420
  return snapshot.finalize();
@@ -19,7 +19,6 @@ import {
19
19
  V1_ClassInstance,
20
20
  V1_ColSpec,
21
21
  V1_ColSpecArray,
22
- V1_Lambda,
23
22
  extractElementNameFromPath as _name,
24
23
  matchFunctionName,
25
24
  type V1_ValueSpecification,
@@ -28,14 +27,11 @@ import { type DataCubeQuerySnapshotColumn } from './DataCubeQuerySnapshot.js';
28
27
  import {
29
28
  assertTrue,
30
29
  assertType,
30
+ guaranteeNonNullable,
31
31
  guaranteeType,
32
- UnsupportedOperationError,
33
32
  type Clazz,
34
33
  } from '@finos/legend-shared';
35
- import {
36
- DataCubeFunction,
37
- DataCubeAggregateOperator,
38
- } from './DataCubeQueryEngine.js';
34
+ import { TREE_COLUMN_VALUE_SEPARATOR } from './DataCubeQueryEngine.js';
39
35
 
40
36
  // --------------------------------- UTILITIES ---------------------------------
41
37
 
@@ -90,108 +86,38 @@ export function _funcMatch(
90
86
  return value;
91
87
  }
92
88
 
93
- // TODO: move these functions out into aggregator utils when we make agg operator handling systematic
94
- // similar to what we did with filter
95
- function _aggFuncMatch(
96
- value: V1_ValueSpecification | undefined,
97
- functionNames: string | string[],
98
- ) {
99
- assertType(
100
- value,
101
- V1_Lambda,
102
- `Can't process aggregation: Found unexpected value specification type`,
103
- );
104
- return _funcMatch(value.body[0], functionNames);
105
- }
89
+ // --------------------------------- BUILDING BLOCKS ---------------------------------
106
90
 
107
- export function _aggCol(
108
- colSpec: V1_ColSpec,
109
- column: DataCubeQuerySnapshotColumn,
91
+ /**
92
+ * This method prunes expanded paths that are no longer valid due to changes in group by columns.
93
+ * It finds the last common group by column between the previous and current group by columns and
94
+ * prune the expanded paths beyond that point.
95
+ */
96
+ export function _pruneExpandedPaths(
97
+ prevGroupByCols: DataCubeQuerySnapshotColumn[],
98
+ currentGroupByCols: DataCubeQuerySnapshotColumn[],
99
+ expandedPaths: string[],
110
100
  ) {
111
- const func = _aggFuncMatch(
112
- colSpec.function2,
113
- Object.values(DataCubeFunction),
114
- );
115
- if (matchFunctionName(func.function, DataCubeFunction.COUNT)) {
116
- return {
117
- ...column,
118
- operation: DataCubeAggregateOperator.COUNT,
119
- parameters: [],
120
- };
121
- } else if (matchFunctionName(func.function, DataCubeFunction.SUM)) {
122
- return {
123
- ...column,
124
- operation: DataCubeAggregateOperator.SUM,
125
- parameters: [],
126
- };
127
- } else if (matchFunctionName(func.function, DataCubeFunction.AVERAGE)) {
128
- return {
129
- ...column,
130
- operation: DataCubeAggregateOperator.AVERAGE,
131
- parameters: [],
132
- };
133
- } else if (matchFunctionName(func.function, DataCubeFunction.MIN)) {
134
- return {
135
- ...column,
136
- operation: DataCubeAggregateOperator.MIN,
137
- parameters: [],
138
- };
139
- } else if (matchFunctionName(func.function, DataCubeFunction.MAX)) {
140
- return {
141
- ...column,
142
- operation: DataCubeAggregateOperator.MAX,
143
- parameters: [],
144
- };
145
- } else if (matchFunctionName(func.function, DataCubeFunction.FIRST)) {
146
- return {
147
- ...column,
148
- operation: DataCubeAggregateOperator.FIRST,
149
- parameters: [],
150
- };
151
- } else if (matchFunctionName(func.function, DataCubeFunction.LAST)) {
152
- return {
153
- ...column,
154
- operation: DataCubeAggregateOperator.LAST,
155
- parameters: [],
156
- };
157
- } else if (
158
- matchFunctionName(func.function, DataCubeFunction.VARIANCE_POPULATION)
159
- ) {
160
- return {
161
- ...column,
162
- operation: DataCubeAggregateOperator.VARIANCE_POPULATION,
163
- parameters: [],
164
- };
165
- } else if (
166
- matchFunctionName(func.function, DataCubeFunction.VARIANCE_SAMPLE)
167
- ) {
168
- return {
169
- ...column,
170
- operation: DataCubeAggregateOperator.VARIANCE_SAMPLE,
171
- parameters: [],
172
- };
173
- } else if (
174
- matchFunctionName(
175
- func.function,
176
- DataCubeFunction.STANDARD_DEVIATION_POPULATION,
177
- )
178
- ) {
179
- return {
180
- ...column,
181
- operation: DataCubeAggregateOperator.STANDARD_DEVIATION_POPULATION,
182
- parameters: [],
183
- };
184
- } else if (
185
- matchFunctionName(func.function, DataCubeFunction.STANDARD_DEVIATION_SAMPLE)
186
- ) {
187
- return {
188
- ...column,
189
- operation: DataCubeAggregateOperator.STANDARD_DEVIATION_SAMPLE,
190
- parameters: [],
191
- };
192
- } else {
193
- throw new UnsupportedOperationError(
194
- `Unsupported aggregate function '${func.function}'`,
195
- );
101
+ const length = Math.min(prevGroupByCols.length, currentGroupByCols.length);
102
+ if (!length) {
103
+ return [];
104
+ }
105
+ let lastCommonIndex = -1;
106
+ for (let i = 0; i < length; i++) {
107
+ if (
108
+ guaranteeNonNullable(prevGroupByCols[i]).name !==
109
+ guaranteeNonNullable(currentGroupByCols[i]).name ||
110
+ guaranteeNonNullable(prevGroupByCols[i]).type !==
111
+ guaranteeNonNullable(currentGroupByCols[i]).type
112
+ ) {
113
+ break;
114
+ }
115
+ lastCommonIndex = i;
196
116
  }
117
+ return expandedPaths
118
+ .filter(
119
+ (path) =>
120
+ path.split(TREE_COLUMN_VALUE_SEPARATOR).length <= lastCommonIndex + 1,
121
+ )
122
+ .sort();
197
123
  }
@@ -63,7 +63,7 @@ export abstract class DataCubeQuerySnapshotController
63
63
  '\nPrevious Snapshot',
64
64
  this.latestSnapshot ?? {},
65
65
  '\nDiff',
66
- deepDiff(snapshot, this.latestSnapshot ?? {}),
66
+ deepDiff(this.latestSnapshot ?? {}, snapshot),
67
67
  );
68
68
  }
69
69
  this.latestSnapshot = snapshot;
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { action, makeObservable, observable } from 'mobx';
18
18
  import type { DataCubeViewState } from '../DataCubeViewState.js';
19
- import type { DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
19
+ import { type DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
20
20
  import type { DataCubeQueryEditorPanelState } from './DataCubeEditorPanelState.js';
21
21
  import type { DataCubeEditorState } from './DataCubeEditorState.js';
22
22
  import { DataCubeEditorMutableConfiguration } from './DataCubeEditorMutableConfiguration.js';
@@ -34,14 +34,15 @@ export class DataCubeEditorGeneralPropertiesPanelState
34
34
 
35
35
  constructor(editor: DataCubeEditorState) {
36
36
  makeObservable(this, {
37
+ configuration: observable,
38
+
37
39
  name: observable,
38
40
  setName: action,
39
41
 
40
42
  limit: observable,
41
43
  setLimit: action,
42
44
 
43
- configuration: observable,
44
- setConfiguration: action,
45
+ applySnaphot: action,
45
46
  });
46
47
 
47
48
  this.editor = editor;
@@ -56,10 +57,6 @@ export class DataCubeEditorGeneralPropertiesPanelState
56
57
  this.limit = val;
57
58
  }
58
59
 
59
- setConfiguration(val: DataCubeEditorMutableConfiguration) {
60
- this.configuration = val;
61
- }
62
-
63
60
  applySnaphot(
64
61
  snapshot: DataCubeQuerySnapshot,
65
62
  configuration: DataCubeConfiguration,
@@ -70,8 +67,8 @@ export class DataCubeEditorGeneralPropertiesPanelState
70
67
  ? snapshot.data.limit
71
68
  : -1,
72
69
  );
73
- this.setConfiguration(
74
- DataCubeEditorMutableConfiguration.create(snapshot.data.configuration),
70
+ this.configuration = DataCubeEditorMutableConfiguration.create(
71
+ snapshot.data.configuration,
75
72
  );
76
73
  }
77
74