@finos/legend-data-cube 0.0.23 → 0.0.25

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 (88) hide show
  1. package/docs/column-configuration.display-value-as-link.md +6 -0
  2. package/docs/column-configuration.kind.md +14 -0
  3. package/docs/column-configuration.missing-value-format.md +5 -0
  4. package/docs/column-configuration.unit.md +5 -0
  5. package/docs/extended-column.level.md +14 -0
  6. package/docs/grid-configuration.row-limit.md +5 -0
  7. package/lib/__lib__/DataCubeDocumentation.d.ts +5 -3
  8. package/lib/__lib__/DataCubeDocumentation.d.ts.map +1 -1
  9. package/lib/__lib__/DataCubeDocumentation.js +5 -3
  10. package/lib/__lib__/DataCubeDocumentation.js.map +1 -1
  11. package/lib/components/core/DataCubeFormUtils.d.ts +1 -0
  12. package/lib/components/core/DataCubeFormUtils.d.ts.map +1 -1
  13. package/lib/components/core/DataCubeFormUtils.js +4 -3
  14. package/lib/components/core/DataCubeFormUtils.js.map +1 -1
  15. package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.d.ts.map +1 -1
  16. package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.js +12 -9
  17. package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.js.map +1 -1
  18. package/lib/components/view/editor/DataCubeEditorColumnSelector.js +2 -2
  19. package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.d.ts.map +1 -1
  20. package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.js +8 -7
  21. package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.js.map +1 -1
  22. package/lib/index.css +2 -2
  23. package/lib/index.css.map +1 -1
  24. package/lib/package.json +1 -1
  25. package/lib/stores/core/DataCubeQueryBuilder.d.ts +3 -0
  26. package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
  27. package/lib/stores/core/DataCubeQueryBuilder.js +8 -1
  28. package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
  29. package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +1 -0
  30. package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
  31. package/lib/stores/core/DataCubeQueryBuilderUtils.js +14 -7
  32. package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
  33. package/lib/stores/core/DataCubeQueryEngine.d.ts +6 -0
  34. package/lib/stores/core/DataCubeQueryEngine.d.ts.map +1 -1
  35. package/lib/stores/core/DataCubeQueryEngine.js +7 -0
  36. package/lib/stores/core/DataCubeQueryEngine.js.map +1 -1
  37. package/lib/stores/core/models/DataCubeConfiguration.d.ts +1 -0
  38. package/lib/stores/core/models/DataCubeConfiguration.d.ts.map +1 -1
  39. package/lib/stores/core/models/DataCubeConfiguration.js +2 -0
  40. package/lib/stores/core/models/DataCubeConfiguration.js.map +1 -1
  41. package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts +2 -2
  42. package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts.map +1 -1
  43. package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.js +4 -3
  44. package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.js.map +1 -1
  45. package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.d.ts +1 -0
  46. package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.d.ts.map +1 -1
  47. package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.js +5 -0
  48. package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.js.map +1 -1
  49. package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts +14 -2
  50. package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts.map +1 -1
  51. package/lib/stores/view/grid/DataCubeGridClientEngine.js +42 -42
  52. package/lib/stores/view/grid/DataCubeGridClientEngine.js.map +1 -1
  53. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts +20 -3
  54. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
  55. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js +81 -35
  56. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
  57. package/lib/stores/view/grid/DataCubeGridMenuBuilder.js +1 -1
  58. package/lib/stores/view/grid/DataCubeGridMenuBuilder.js.map +1 -1
  59. package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts +3 -3
  60. package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
  61. package/lib/stores/view/grid/DataCubeGridQueryBuilder.js +39 -8
  62. package/lib/stores/view/grid/DataCubeGridQueryBuilder.js.map +1 -1
  63. package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.d.ts +2 -2
  64. package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.d.ts.map +1 -1
  65. package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.js +30 -14
  66. package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.js.map +1 -1
  67. package/lib/stores/view/grid/DataCubeGridState.d.ts +2 -0
  68. package/lib/stores/view/grid/DataCubeGridState.d.ts.map +1 -1
  69. package/lib/stores/view/grid/DataCubeGridState.js +5 -1
  70. package/lib/stores/view/grid/DataCubeGridState.js.map +1 -1
  71. package/package.json +4 -4
  72. package/src/__lib__/DataCubeDocumentation.ts +5 -3
  73. package/src/components/core/DataCubeFormUtils.tsx +5 -1
  74. package/src/components/view/editor/DataCubeEditorColumnPropertiesPanel.tsx +40 -14
  75. package/src/components/view/editor/DataCubeEditorColumnSelector.tsx +2 -2
  76. package/src/components/view/editor/DataCubeEditorGeneralPropertiesPanel.tsx +41 -30
  77. package/src/stores/core/DataCubeQueryBuilder.ts +13 -0
  78. package/src/stores/core/DataCubeQueryBuilderUtils.ts +32 -6
  79. package/src/stores/core/DataCubeQueryEngine.ts +8 -0
  80. package/src/stores/core/models/DataCubeConfiguration.ts +2 -0
  81. package/src/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.ts +5 -4
  82. package/src/stores/view/editor/DataCubeEditorMutableConfiguration.ts +7 -0
  83. package/src/stores/view/grid/DataCubeGridClientEngine.ts +56 -51
  84. package/src/stores/view/grid/DataCubeGridConfigurationBuilder.tsx +90 -37
  85. package/src/stores/view/grid/DataCubeGridMenuBuilder.tsx +1 -1
  86. package/src/stores/view/grid/DataCubeGridQueryBuilder.ts +70 -14
  87. package/src/stores/view/grid/DataCubeGridQuerySnapshotBuilder.ts +40 -20
  88. package/src/stores/view/grid/DataCubeGridState.ts +12 -1
@@ -46,6 +46,7 @@ import {
46
46
  _primitiveValue,
47
47
  _var,
48
48
  _functionCompositionProcessor,
49
+ _extendRootAggregation,
49
50
  } from './DataCubeQueryBuilderUtils.js';
50
51
  import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
51
52
  import type { DataCubeSource } from './models/DataCubeSource.js';
@@ -67,6 +68,11 @@ export function buildExecutableQuery(
67
68
  filterOperations: DataCubeQueryFilterOperation[],
68
69
  aggregateOperations: DataCubeQueryAggregateOperation[],
69
70
  ) => void;
71
+ rootAggregation?:
72
+ | {
73
+ columnName: string;
74
+ }
75
+ | undefined;
70
76
  pagination?:
71
77
  | {
72
78
  start: number;
@@ -91,6 +97,8 @@ export function buildExecutableQuery(
91
97
  _col(col.name, _deserializeLambda(col.mapFn)),
92
98
  ]),
93
99
  );
100
+ // instead of batching all the extend() functions, we sequence them, and reference the first one
101
+ // in the function map
94
102
  _process('leafExtend', guaranteeNonNullable(leafExtendedFuncs[0]));
95
103
  leafExtendedFuncs.slice(1).forEach((func) => {
96
104
  sequence.push(func);
@@ -163,6 +171,9 @@ export function buildExecutableQuery(
163
171
 
164
172
  if (data.groupBy) {
165
173
  const groupBy = data.groupBy;
174
+ if (configuration.showRootAggregation && options?.rootAggregation) {
175
+ sequence.push(_extendRootAggregation(options.rootAggregation.columnName));
176
+ }
166
177
  _process(
167
178
  'groupBy',
168
179
  _function(DataCubeFunction.GROUP_BY, [
@@ -203,6 +214,8 @@ export function buildExecutableQuery(
203
214
  _col(col.name, _deserializeLambda(col.mapFn)),
204
215
  ]),
205
216
  );
217
+ // instead of batching all the extend() functions, we sequence them, and reference the first one
218
+ // in the function map
206
219
  _process('groupExtend', guaranteeNonNullable(groupExtendedFuncs[0]));
207
220
  groupExtendedFuncs.slice(1).forEach((func) => {
208
221
  sequence.push(func);
@@ -49,6 +49,10 @@ import {
49
49
  extractPackagePathFromPath,
50
50
  CORE_PURE_PATH,
51
51
  V1_GenericTypeInstance,
52
+ V1_createGenericTypeWithElementPath,
53
+ V1_createGenericTypeWithRawType,
54
+ V1_createRelationType,
55
+ V1_createRelationTypeColumn,
52
56
  } from '@finos/legend-graph';
53
57
  import {
54
58
  type DataCubeQuerySnapshotFilterCondition,
@@ -75,6 +79,7 @@ import {
75
79
  type DataCubeQueryFunctionMap,
76
80
  isPivotResultColumnName,
77
81
  getPivotResultColumnBaseColumnName,
82
+ DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE,
78
83
  } from './DataCubeQueryEngine.js';
79
84
  import type { DataCubeQueryFilterOperation } from './filter/DataCubeQueryFilterOperation.js';
80
85
  import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
@@ -380,14 +385,18 @@ export function _pivotAggCols(
380
385
  }
381
386
 
382
387
  export function _castCols(columns: DataCubeColumn[]) {
383
- const genericType = new V1_GenericTypeInstance();
384
- genericType.fullPath = CORE_PURE_PATH.RELATION;
385
- genericType.typeArguments = [
386
- _cols(
387
- columns.map((col) => _colSpec(col.name, undefined, undefined, col.type)),
388
+ const genericTypeInstance = new V1_GenericTypeInstance();
389
+ genericTypeInstance.genericType = V1_createGenericTypeWithElementPath(
390
+ CORE_PURE_PATH.RELATION,
391
+ );
392
+ genericTypeInstance.genericType.typeArguments = [
393
+ V1_createGenericTypeWithRawType(
394
+ V1_createRelationType(
395
+ columns.map((col) => V1_createRelationTypeColumn(col.name, col.type)),
396
+ ),
388
397
  ),
389
398
  ];
390
- return genericType;
399
+ return genericTypeInstance;
391
400
  }
392
401
 
393
402
  export function _groupByAggCols(
@@ -487,6 +496,23 @@ export function _groupByAggCols(
487
496
  ]);
488
497
  }
489
498
 
499
+ export function _extendRootAggregation(columnName: string) {
500
+ return _function(DataCubeFunction.EXTEND, [
501
+ _col(
502
+ columnName,
503
+ _lambda(
504
+ [_var()],
505
+ [
506
+ _primitiveValue(
507
+ PRIMITIVE_TYPE.STRING,
508
+ DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE,
509
+ ),
510
+ ],
511
+ ),
512
+ ),
513
+ ]);
514
+ }
515
+
490
516
  export function _filter(
491
517
  filter: DataCubeQuerySnapshotFilter | DataCubeQuerySnapshotFilterCondition,
492
518
  filterOperations: DataCubeQueryFilterOperation[],
@@ -305,6 +305,7 @@ export const DEFAULT_REPORT_NAME = 'New Report';
305
305
  export const DEFAULT_TREE_COLUMN_SORT_DIRECTION =
306
306
  DataCubeQuerySortDirection.ASCENDING;
307
307
  export const DEFAULT_PIVOT_STATISTIC_COLUMN_NAME = 'Total';
308
+ export const DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE = '[ROOT]';
308
309
 
309
310
  export const DEFAULT_URL_LABEL_QUERY_PARAM = 'dataCube.linkLabel';
310
311
  export const DEFAULT_MISSING_VALUE_DISPLAY_TEXT = '';
@@ -330,3 +331,10 @@ export const DEFAULT_ROW_BACKGROUND_COLOR = TailwindCSSPalette.white;
330
331
  export const DEFAULT_NEGATIVE_FOREGROUND_COLOR = TailwindCSSPalette.red[500];
331
332
  export const DEFAULT_ZERO_FOREGROUND_COLOR = TailwindCSSPalette.neutral[400];
332
333
  export const DEFAULT_ERROR_FOREGROUND_COLOR = TailwindCSSPalette.blue[600];
334
+
335
+ // settings
336
+ export const TAB_SIZE = 2;
337
+ export const DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
338
+ export const TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH = 3;
339
+ export const TYPEAHEAD_SEARCH_LIMIT = 10;
340
+ export const EMPTY_VALUE_PLACEHOLDER = '(None)';
@@ -63,6 +63,7 @@ export class DataCubeColumnConfiguration {
63
63
  negativeNumberInParens = false;
64
64
  numberScale?: DataCubeNumberScale | undefined;
65
65
  missingValueDisplayText?: string | undefined;
66
+ unit?: string | undefined;
66
67
 
67
68
  fontFamily?: DataCubeFont | undefined;
68
69
  fontSize?: number | undefined;
@@ -154,6 +155,7 @@ export class DataCubeColumnConfiguration {
154
155
  pivotStatisticColumnFunction: optional(primitive()),
155
156
  textAlign: optional(primitive()),
156
157
  type: primitive(),
158
+ unit: optional(primitive()),
157
159
  zeroBackgroundColor: optional(primitive()),
158
160
  zeroForegroundColor: optional(primitive()),
159
161
  }),
@@ -28,7 +28,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
28
28
  readonly view!: DataCubeViewState;
29
29
  readonly editor!: DataCubeEditorState;
30
30
 
31
- limit = -1;
31
+ limit: number | undefined = undefined;
32
32
  configuration = new DataCubeEditorMutableConfiguration();
33
33
 
34
34
  constructor(editor: DataCubeEditorState) {
@@ -45,7 +45,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
45
45
  this.view = editor.view;
46
46
  }
47
47
 
48
- setLimit(val: number) {
48
+ setLimit(val: number | undefined): void {
49
49
  this.limit = val;
50
50
  }
51
51
 
@@ -56,7 +56,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
56
56
  this.setLimit(
57
57
  snapshot.data.limit !== undefined && snapshot.data.limit >= 0
58
58
  ? snapshot.data.limit
59
- : -1,
59
+ : undefined,
60
60
  );
61
61
  this.configuration = DataCubeEditorMutableConfiguration.create(
62
62
  snapshot.data.configuration,
@@ -68,7 +68,8 @@ export class DataCubeEditorGeneralPropertiesPanelState
68
68
  baseSnapshot: DataCubeQuerySnapshot,
69
69
  ) {
70
70
  const data = newSnapshot.data;
71
- data.limit = this.limit < 0 ? undefined : this.limit;
71
+ data.limit =
72
+ this.limit === undefined || this.limit < 0 ? undefined : this.limit;
72
73
  data.configuration = this.configuration.serialize();
73
74
  }
74
75
  }
@@ -96,6 +96,9 @@ export class DataCubeEditorMutableColumnConfiguration extends DataCubeColumnConf
96
96
  missingValueDisplayText: observable,
97
97
  setMissingValueDisplayText: action,
98
98
 
99
+ unit: observable,
100
+ setUnit: action,
101
+
99
102
  fontFamily: observable,
100
103
  setFontFamily: action,
101
104
 
@@ -273,6 +276,10 @@ export class DataCubeEditorMutableColumnConfiguration extends DataCubeColumnConf
273
276
  this.missingValueDisplayText = value;
274
277
  }
275
278
 
279
+ setUnit(value: string | undefined) {
280
+ this.unit = value;
281
+ }
282
+
276
283
  setFontFamily(value: DataCubeFont | undefined) {
277
284
  this.fontFamily = value;
278
285
  }
@@ -32,7 +32,6 @@ import {
32
32
  } from '@finos/legend-shared';
33
33
  import { buildExecutableQuery } from '../../core/DataCubeQueryBuilder.js';
34
34
  import { type TabularDataSet, V1_Lambda } from '@finos/legend-graph';
35
- import { generateRowGroupingDrilldownExecutableQueryPostProcessor } from './DataCubeGridQueryBuilder.js';
36
35
  import { makeObservable, observable, runInAction } from 'mobx';
37
36
  import type {
38
37
  DataCubeConfiguration,
@@ -49,10 +48,11 @@ import { buildQuerySnapshot } from './DataCubeGridQuerySnapshotBuilder.js';
49
48
  import { AlertType } from '../../../components/core/DataCubeAlert.js';
50
49
  import { sum } from 'mathjs';
51
50
  import type { DataCubeViewState } from '../DataCubeViewState.js';
51
+ import { buildGridDataFetchExecutableQuery } from './DataCubeGridQueryBuilder.js';
52
52
 
53
- type GridClientCellValue = string | number | boolean | null | undefined;
54
- type GridClientRowData = {
55
- [key: string]: GridClientCellValue;
53
+ type DataCubeGridClientCellValue = string | number | boolean | null | undefined;
54
+ type DataCubeGridClientRowData = {
55
+ [key: string]: DataCubeGridClientCellValue;
56
56
  };
57
57
 
58
58
  export enum DataCubeGridClientExportFormat {
@@ -128,17 +128,19 @@ export const INTERNAL__GRID_CLIENT_TOOLTIP_SHOW_DELAY = 1500;
128
128
  export const INTERNAL__GRID_CLIENT_AUTO_RESIZE_PADDING = 10;
129
129
  export const INTERNAL__GRID_CLIENT_MISSING_VALUE = '__MISSING';
130
130
  export const INTERNAL__GRID_CLIENT_TREE_COLUMN_ID = 'ag-Grid-AutoColumn';
131
+ export const INTERNAL__GRID_CLIENT_ROOT_AGGREGATION_COLUMN_ID =
132
+ 'INTERNAL__rootAggregation';
131
133
  export const INTERNAL__GRID_CLIENT_DATA_FETCH_MANUAL_TRIGGER_COLUMN_ID =
132
134
  'INTERNAL__dataFetchManualTrigger';
133
135
  export const INTERNAL__GRID_CLIENT_ROW_GROUPING_COUNT_AGG_COLUMN_ID =
134
136
  'INTERNAL__count';
135
137
 
136
- export enum GridClientPinnedAlignement {
138
+ export enum DataCubeGridClientPinnedAlignement {
137
139
  LEFT = 'left',
138
140
  RIGHT = 'right',
139
141
  }
140
142
 
141
- export enum GridClientSortDirection {
143
+ export enum DataCubeGridClientSortDirection {
142
144
  ASCENDING = 'asc',
143
145
  DESCENDING = 'desc',
144
146
  }
@@ -209,9 +211,9 @@ export function computeHashCodeForDataFetchManualTrigger(
209
211
  function buildRowData(
210
212
  result: TabularDataSet,
211
213
  snapshot: DataCubeQuerySnapshot,
212
- ): GridClientRowData[] {
214
+ ): DataCubeGridClientRowData[] {
213
215
  return result.rows.map((_row, rowIdx) => {
214
- const row: GridClientRowData = {};
216
+ const row: DataCubeGridClientRowData = {};
215
217
  const cols = result.columns;
216
218
  _row.values.forEach((value, colIdx) => {
217
219
  // `ag-grid` shows `false` value as empty string so we have
@@ -299,6 +301,18 @@ async function getCastColumns(
299
301
  }));
300
302
  }
301
303
 
304
+ export type DataCubeGridClientDataFetchRequest = {
305
+ startRow: number | undefined;
306
+ endRow: number | undefined;
307
+ rowGroupColumns: string[];
308
+ groupKeys: (string | null | undefined)[]; // NOTE: it's possible for these values to be nullish depending on row data
309
+ pivotColumns: string[];
310
+ sortColumns: {
311
+ name: string;
312
+ direction: DataCubeGridClientSortDirection;
313
+ }[];
314
+ };
315
+
302
316
  export class DataCubeGridClientServerSideDataSource
303
317
  implements IServerSideDatasource
304
318
  {
@@ -316,39 +330,34 @@ export class DataCubeGridClientServerSideDataSource
316
330
  async fetchRows(params: IServerSideGetRowsParams<unknown, unknown>) {
317
331
  const task = this.grid.view.newTask('Fetching data');
318
332
 
319
- // ------------------------------ GRID OPTIONS ------------------------------
320
- // Here, we make adjustments to the grid display in response to the new
321
- // request, in case the grid action has not impacted the layout in an
322
- // adequate way.
323
-
324
- // Toggle the visibility of the tree column based on the presence of row-group columns
325
- if (params.request.rowGroupCols.length) {
326
- params.api.setColumnsVisible(
327
- [INTERNAL__GRID_CLIENT_TREE_COLUMN_ID],
328
- true,
329
- );
330
- } else {
331
- params.api.setColumnsVisible(
332
- [INTERNAL__GRID_CLIENT_TREE_COLUMN_ID],
333
- false,
334
- );
335
- }
336
-
337
333
  // ------------------------------ SNAPSHOT ------------------------------
338
334
 
339
335
  const currentSnapshot = guaranteeNonNullable(this.grid.getLatestSnapshot());
336
+ const request: DataCubeGridClientDataFetchRequest = {
337
+ startRow: params.request.startRow,
338
+ endRow: params.request.endRow,
339
+ rowGroupColumns: params.request.rowGroupCols.map((col) => col.id),
340
+ groupKeys: params.request.groupKeys.map((key) => key),
341
+ pivotColumns: params.request.pivotCols.map((col) => col.id),
342
+ sortColumns: params.request.sortModel.map((item) => ({
343
+ name: item.colId,
344
+ direction: item.sort as DataCubeGridClientSortDirection,
345
+ })),
346
+ };
347
+ const isTopLevelRequest = request.groupKeys.length === 0;
348
+
340
349
  let newSnapshot = currentSnapshot;
341
350
 
342
351
  // only recompute the snapshot if this is not a drilldown request
343
- if (params.request.groupKeys.length === 0) {
344
- newSnapshot = buildQuerySnapshot(params.request, currentSnapshot);
352
+ if (isTopLevelRequest) {
353
+ newSnapshot = buildQuerySnapshot(request, currentSnapshot);
345
354
 
346
355
  // NOTE: if h-pivot is enabled, update the cast columns
347
356
  // and panels which might be affected by this (e.g. sorts)
348
357
  // Because is an expensive operation in certain case, we only
349
358
  // recompute when it's not a drilldown or paging request,
350
359
  // but we could still optimize further if needed.
351
- if (!this.grid.isPaginationEnabled || params.request.startRow === 0) {
360
+ if (!this.grid.isPaginationEnabled || request.startRow === 0) {
352
361
  if (newSnapshot.data.pivot) {
353
362
  try {
354
363
  const castColumns = await getCastColumns(
@@ -390,27 +399,14 @@ export class DataCubeGridClientServerSideDataSource
390
399
  // ------------------------------ DATA ------------------------------
391
400
 
392
401
  try {
393
- const executableQuery = buildExecutableQuery(
402
+ const executableQuery = buildGridDataFetchExecutableQuery(
403
+ request,
394
404
  newSnapshot,
395
405
  this.grid.view.source,
396
406
  (source) => this.grid.view.engine.buildExecutionContext(source),
397
407
  this.grid.view.engine.filterOperations,
398
408
  this.grid.view.engine.aggregateOperations,
399
- {
400
- postProcessor:
401
- generateRowGroupingDrilldownExecutableQueryPostProcessor(
402
- params.request.groupKeys,
403
- ),
404
- pagination:
405
- this.grid.isPaginationEnabled &&
406
- params.request.startRow !== undefined &&
407
- params.request.endRow !== undefined
408
- ? {
409
- start: params.request.startRow,
410
- end: params.request.endRow,
411
- }
412
- : undefined,
413
- },
409
+ this.grid.isPaginationEnabled,
414
410
  );
415
411
  const lambda = new V1_Lambda();
416
412
  lambda.body.push(executableQuery);
@@ -436,16 +432,16 @@ export class DataCubeGridClientServerSideDataSource
436
432
  if (this.grid.isPaginationEnabled) {
437
433
  params.success({ rowData });
438
434
  // only update row count when loading the top-level drilldown data
439
- if (params.request.groupKeys.length === 0) {
435
+ if (isTopLevelRequest) {
440
436
  runInAction(() => {
441
- this.rowCount = (params.request.startRow ?? 0) + rowData.length;
437
+ this.rowCount = (request.startRow ?? 0) + rowData.length;
442
438
  });
443
439
  }
444
440
 
445
441
  // toggle no-rows overlay
446
442
  if (
447
- params.request.groupKeys.length === 0 &&
448
- params.request.startRow === 0 &&
443
+ isTopLevelRequest &&
444
+ request.startRow === 0 &&
449
445
  rowData.length === 0
450
446
  ) {
451
447
  this.grid.client.showNoRowsOverlay();
@@ -506,19 +502,28 @@ export class DataCubeGridClientServerSideDataSource
506
502
  });
507
503
 
508
504
  // only update row count when loading the top-level drilldown data
509
- if (params.request.groupKeys.length === 0) {
505
+ if (isTopLevelRequest) {
510
506
  runInAction(() => {
511
507
  this.rowCount = rowData.length;
512
508
  });
513
509
  }
514
510
 
515
511
  // toggle no-rows overlay
516
- if (params.request.groupKeys.length === 0 && rowData.length === 0) {
512
+ if (isTopLevelRequest && rowData.length === 0) {
517
513
  this.grid.client.showNoRowsOverlay();
518
514
  } else {
519
515
  this.grid.client.hideOverlay();
520
516
  }
521
517
  }
518
+
519
+ // Resize columns to fit content on all actions (drilldown, changing queries, fetching new page, etc.)
520
+ // NOTE: we might want to restrict this to only happen on certain actions
521
+ //
522
+ // `setTimeout()` is need to ensure this runs after the grid has been updated with the new data
523
+ // since ag-grid does not provide an event hook for this action for server-side row model.
524
+ setTimeout(() => {
525
+ this.grid.client.autoSizeAllColumns();
526
+ }, 0);
522
527
  } catch (error) {
523
528
  assertErrorThrown(error);
524
529
  this.grid.view.engine.alertError(error, {