@finos/legend-query-builder 2.0.0 → 2.1.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 (43) hide show
  1. package/lib/components/QueryBuilder.js +1 -1
  2. package/lib/components/QueryBuilder.js.map +1 -1
  3. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  4. package/lib/components/QueryBuilderResultPanel.js +15 -5
  5. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  6. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  7. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +19 -17
  8. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  9. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +34 -31
  11. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  12. package/lib/index.css +2 -2
  13. package/lib/index.css.map +1 -1
  14. package/lib/package.json +3 -3
  15. package/lib/stores/QueryBuilderResultState.d.ts +7 -3
  16. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  17. package/lib/stores/QueryBuilderResultState.js +14 -20
  18. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  19. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts +3 -0
  20. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts.map +1 -1
  21. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js.map +1 -1
  22. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts +10 -1
  23. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
  24. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +36 -1
  25. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
  26. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts +6 -0
  27. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
  28. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +21 -2
  29. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
  30. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts +1 -0
  31. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts.map +1 -1
  32. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js +10 -1
  33. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js.map +1 -1
  34. package/package.json +10 -10
  35. package/src/components/QueryBuilder.tsx +1 -1
  36. package/src/components/QueryBuilderResultPanel.tsx +30 -17
  37. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +128 -126
  38. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +262 -256
  39. package/src/stores/QueryBuilderResultState.ts +28 -33
  40. package/src/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.ts +5 -0
  41. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.ts +44 -0
  42. package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +28 -0
  43. package/src/stores/fetch-structure/tds/window/QueryBuilderWindowState.ts +14 -1
@@ -20,26 +20,26 @@ import {
20
20
  assertErrorThrown,
21
21
  LogEvent,
22
22
  guaranteeNonNullable,
23
- ContentType,
24
- guaranteeType,
23
+ type ContentType,
25
24
  downloadFileUsingDataURI,
26
- UnsupportedOperationError,
27
25
  ActionState,
28
26
  StopWatch,
27
+ getContentTypeFileExtension,
29
28
  } from '@finos/legend-shared';
30
29
  import type { QueryBuilderState } from './QueryBuilderState.js';
31
30
  import {
32
31
  type RawExecutionPlan,
33
32
  type ExecutionResult,
34
33
  type RawLambda,
34
+ type EXECUTION_SERIALIZATION_FORMAT,
35
35
  GRAPH_MANAGER_EVENT,
36
- EXECUTION_SERIALIZATION_FORMAT,
37
36
  RawExecutionResult,
38
37
  buildRawLambdaFromLambdaFunction,
39
38
  reportGraphAnalytics,
39
+ extractExecutionResultValues,
40
40
  } from '@finos/legend-graph';
41
41
  import { buildLambdaFunction } from './QueryBuilderValueSpecificationBuilder.js';
42
- import { ExecutionPlanState } from '@finos/legend-application';
42
+ import { ExecutionPlanState, TAB_SIZE } from '@finos/legend-application';
43
43
  import {
44
44
  buildExecutionParameterValues,
45
45
  getExecutionQueryFromRawLambda,
@@ -50,6 +50,11 @@ import { QUERY_BUILDER_EVENT } from '../application/QueryBuilderEvent.js';
50
50
 
51
51
  const DEFAULT_LIMIT = 1000;
52
52
 
53
+ export interface ExportDataInfo {
54
+ contentType: ContentType;
55
+ serializationFormat?: EXECUTION_SERIALIZATION_FORMAT | undefined;
56
+ }
57
+
53
58
  export class QueryBuilderResultState {
54
59
  readonly queryBuilderState: QueryBuilderState;
55
60
  readonly exportDataState = ActionState.create();
@@ -148,25 +153,21 @@ export class QueryBuilderResultState {
148
153
  return query;
149
154
  }
150
155
 
151
- *exportData(
152
- serializationFormat: EXECUTION_SERIALIZATION_FORMAT,
153
- ): GeneratorFn<void> {
156
+ *exportData(format: string): GeneratorFn<void> {
154
157
  try {
158
+ const exportData =
159
+ this.queryBuilderState.fetchStructureState.implementation.getExportDataInfo(
160
+ format,
161
+ );
162
+ const contentType = exportData.contentType;
163
+ const serializationFormat = exportData.serializationFormat;
155
164
  this.exportDataState.inProgress();
156
- const mapping = guaranteeNonNullable(
157
- this.queryBuilderState.mapping,
158
- 'Mapping is required to execute query',
159
- );
160
- const runtime = guaranteeNonNullable(
161
- this.queryBuilderState.runtimeValue,
162
- `Runtime is required to execute query`,
163
- );
164
165
  const query = this.buildExecutionRawLambda();
165
166
  const result =
166
167
  (yield this.queryBuilderState.graphManagerState.graphManager.runQuery(
167
168
  query,
168
- mapping,
169
- runtime,
169
+ this.queryBuilderState.mapping,
170
+ this.queryBuilderState.runtimeValue,
170
171
  this.queryBuilderState.graphManagerState.graph,
171
172
  {
172
173
  serializationFormat,
@@ -176,23 +177,17 @@ export class QueryBuilderResultState {
176
177
  ),
177
178
  },
178
179
  )) as ExecutionResult;
179
- let contentType: ContentType;
180
- let fileName = 'result';
181
180
  let content: string;
182
- switch (serializationFormat) {
183
- case EXECUTION_SERIALIZATION_FORMAT.CSV:
184
- {
185
- const rawResult = guaranteeType(result, RawExecutionResult);
186
- contentType = ContentType.TEXT_CSV;
187
- fileName = `${fileName}.csv`;
188
- content = rawResult.value;
189
- }
190
- break;
191
- default:
192
- throw new UnsupportedOperationError(
193
- `Can't download file for serialization type: '${serializationFormat}'`,
194
- );
181
+ if (result instanceof RawExecutionResult) {
182
+ content = result.value;
183
+ } else {
184
+ content = JSON.stringify(
185
+ extractExecutionResultValues(result),
186
+ null,
187
+ TAB_SIZE,
188
+ );
195
189
  }
190
+ const fileName = `result.${getContentTypeFileExtension(contentType)}`;
196
191
  downloadFileUsingDataURI(fileName, content, contentType);
197
192
  this.exportDataState.pass();
198
193
  } catch (error) {
@@ -26,6 +26,7 @@ import type { QueryBuilderExplorerTreePropertyNodeData } from '../explorer/Query
26
26
  import type { QueryBuilderState } from '../QueryBuilderState.js';
27
27
  import type { LambdaFunctionBuilderOption } from '../QueryBuilderValueSpecificationBuilderHelper.js';
28
28
  import type { QueryBuilderFetchStructureState } from './QueryBuilderFetchStructureState.js';
29
+ import type { ExportDataInfo } from '../QueryBuilderResultState.js';
29
30
 
30
31
  export enum FETCH_STRUCTURE_IMPLEMENTATION {
31
32
  TABULAR_DATA_STRUCTURE = 'TABULAR_DATA_STRUCTURE',
@@ -75,4 +76,8 @@ export abstract class QueryBuilderFetchStructureImplementationState
75
76
  get TEMPORARY__showPostFetchStructurePanel(): boolean {
76
77
  return this.queryBuilderState.filterState.showPanel;
77
78
  }
79
+
80
+ // export options
81
+ abstract get exportDataFormatOptions(): string[];
82
+ abstract getExportDataInfo(format: string): ExportDataInfo;
78
83
  }
@@ -51,15 +51,22 @@ import {
51
51
  guaranteeNonNullable,
52
52
  hashArray,
53
53
  type Hashable,
54
+ UnsupportedOperationError,
55
+ ContentType,
54
56
  } from '@finos/legend-shared';
55
57
  import { QUERY_BUILDER_HASH_STRUCTURE } from '../../../graphManager/QueryBuilderHashUtils.js';
56
58
  import { isValueExpressionReferencedInValue } from '../../QueryBuilderValueSpecificationHelper.js';
59
+ import type { ExportDataInfo } from '../../QueryBuilderResultState.js';
57
60
 
58
61
  export enum SERIALIZATION_TYPE {
59
62
  PURE = 'PURE',
60
63
  EXTERNAL_FORMAT = 'EXTERNAL_FORMAT',
61
64
  }
62
65
 
66
+ export enum GRAPH_FETCH_EXPORT_DATA_FORMAT {
67
+ RESULT = 'RESULT',
68
+ }
69
+
63
70
  const DEFAULT_PURE_CONFIG_TYPE_NAME = '@type';
64
71
 
65
72
  export class PureSerializationConfig {
@@ -135,6 +142,8 @@ export abstract class GraphFetchSerializationState {
135
142
  }
136
143
 
137
144
  abstract getLabel(): string;
145
+
146
+ abstract get serializationContentType(): ContentType;
138
147
  }
139
148
 
140
149
  export class GraphFetchPureSerializationState extends GraphFetchSerializationState {
@@ -161,6 +170,10 @@ export class GraphFetchPureSerializationState extends GraphFetchSerializationSta
161
170
  override getLabel(): string {
162
171
  return SERIALIZATION_TYPE.PURE;
163
172
  }
173
+
174
+ override get serializationContentType(): ContentType {
175
+ return ContentType.APPLICATION_JSON;
176
+ }
164
177
  }
165
178
 
166
179
  export class GraphFetchExternalFormatSerializationState extends GraphFetchSerializationState {
@@ -176,6 +189,7 @@ export class GraphFetchExternalFormatSerializationState extends GraphFetchSerial
176
189
  makeObservable(this, {
177
190
  targetBinding: observable,
178
191
  treeData: observable.ref,
192
+ serializationContentType: computed,
179
193
  });
180
194
  this.targetBinding = targetBinding;
181
195
  this.treeData = treeData;
@@ -192,6 +206,20 @@ export class GraphFetchExternalFormatSerializationState extends GraphFetchSerial
192
206
  override getLabel(): string {
193
207
  return SERIALIZATION_TYPE.EXTERNAL_FORMAT;
194
208
  }
209
+
210
+ override get serializationContentType(): ContentType {
211
+ const contentType = this.targetBinding.contentType;
212
+ if (Object.values(ContentType).includes(contentType as ContentType)) {
213
+ return contentType as ContentType;
214
+ } else {
215
+ // TEMP: need to investigate if flatdata should be returned as content type
216
+ // for now we will assume all flatdata is csv
217
+ if (contentType === 'application/x.flatdata') {
218
+ return ContentType.TEXT_CSV;
219
+ }
220
+ return ContentType.TEXT_PLAIN;
221
+ }
222
+ }
195
223
  }
196
224
 
197
225
  export class QueryBuilderGraphFetchTreeState
@@ -321,6 +349,22 @@ export class QueryBuilderGraphFetchTreeState
321
349
  );
322
350
  }
323
351
 
352
+ override get exportDataFormatOptions(): string[] {
353
+ return [GRAPH_FETCH_EXPORT_DATA_FORMAT.RESULT];
354
+ }
355
+
356
+ override getExportDataInfo(format: string): ExportDataInfo {
357
+ if (format === GRAPH_FETCH_EXPORT_DATA_FORMAT.RESULT) {
358
+ return {
359
+ contentType: this.serializationState.serializationContentType,
360
+ };
361
+ } else {
362
+ throw new UnsupportedOperationError(
363
+ `Unsupported Graph Fetch export type ${format}`,
364
+ );
365
+ }
366
+ }
367
+
324
368
  onClassChange(_class: Class | undefined): void {
325
369
  this.updateTreeData(_class);
326
370
  }
@@ -35,6 +35,8 @@ import {
35
35
  filterByType,
36
36
  type Hashable,
37
37
  hashArray,
38
+ UnsupportedOperationError,
39
+ ContentType,
38
40
  } from '@finos/legend-shared';
39
41
  import type { QueryBuilderState } from '../../QueryBuilderState.js';
40
42
  import {
@@ -52,6 +54,7 @@ import {
52
54
  matchFunctionName,
53
55
  SimpleFunctionExpression,
54
56
  getAllSuperclasses,
57
+ EXECUTION_SERIALIZATION_FORMAT,
55
58
  } from '@finos/legend-graph';
56
59
  import {
57
60
  DEFAULT_LAMBDA_VARIABLE_NAME,
@@ -97,6 +100,12 @@ import type { QueryBuilderTDS_WindowOperator } from './window/operators/QueryBui
97
100
  import { getQueryBuilderCoreWindowOperators } from './window/QueryBuilderWindowGroupByOperatorLoader.js';
98
101
  import type { QueryBuilderTDSColumnState } from './QueryBuilderTDSColumnState.js';
99
102
  import { QUERY_BUILDER_SETTING_KEY } from '../../../application/QueryBuilderSetting.js';
103
+ import type { ExportDataInfo } from '../../QueryBuilderResultState.js';
104
+
105
+ // TODO: should we support raw once externalize() is supported on TDS ?
106
+ export enum TDS_EXECUTION_SERIALIZATION_FORMAT {
107
+ CSV = 'CSV',
108
+ }
100
109
 
101
110
  export class QueryBuilderTDSState
102
111
  extends QueryBuilderFetchStructureImplementationState
@@ -289,6 +298,25 @@ export class QueryBuilderTDSState
289
298
  ];
290
299
  }
291
300
 
301
+ override get exportDataFormatOptions(): string[] {
302
+ return [TDS_EXECUTION_SERIALIZATION_FORMAT.CSV];
303
+ }
304
+
305
+ override getExportDataInfo(format: string): ExportDataInfo {
306
+ switch (format) {
307
+ case TDS_EXECUTION_SERIALIZATION_FORMAT.CSV:
308
+ return {
309
+ contentType: ContentType.TEXT_CSV,
310
+ serializationFormat: EXECUTION_SERIALIZATION_FORMAT.CSV,
311
+ };
312
+
313
+ default:
314
+ throw new UnsupportedOperationError(
315
+ `Unsupported TDS export type ${format}`,
316
+ );
317
+ }
318
+ }
319
+
292
320
  isDuplicateColumn(col: QueryBuilderTDSColumnState): boolean {
293
321
  return (
294
322
  this.tdsColumns.filter((c) => c.columnName === col.columnName).length > 1
@@ -23,7 +23,7 @@ import {
23
23
  uniq,
24
24
  type Hashable,
25
25
  } from '@finos/legend-shared';
26
- import { action, makeObservable, observable } from 'mobx';
26
+ import { action, computed, makeObservable, observable } from 'mobx';
27
27
  import { QUERY_BUILDER_HASH_STRUCTURE } from '../../../../graphManager/QueryBuilderHashUtils.js';
28
28
  import { DEFAULT_LAMBDA_VARIABLE_NAME } from '../../../QueryBuilderConfig.js';
29
29
  import type { QueryBuilderProjectionColumnDragSource } from '../projection/QueryBuilderProjectionColumnState.js';
@@ -333,6 +333,7 @@ export class QueryBuilderWindowState implements Hashable {
333
333
  makeObservable(this, {
334
334
  windowColumns: observable,
335
335
  editColumn: observable,
336
+ validationIssues: computed,
336
337
  addWindowColumn: action,
337
338
  removeColumn: action,
338
339
  moveColumn: action,
@@ -346,6 +347,18 @@ export class QueryBuilderWindowState implements Hashable {
346
347
  return !this.windowColumns.length;
347
348
  }
348
349
 
350
+ get validationIssues(): string[] | undefined {
351
+ const hasDuplicatedWindowColumns = this.windowColumns.some(
352
+ (column) =>
353
+ this.windowColumns.filter((c) => c.columnName === column.columnName)
354
+ .length > 1,
355
+ );
356
+ if (hasDuplicatedWindowColumns) {
357
+ return ['Query has duplicated window columns'];
358
+ }
359
+ return undefined;
360
+ }
361
+
349
362
  get referencedTDSColumns(): QueryBuilderTDSColumnState[] {
350
363
  return uniq(this.windowColumns.map((c) => c.referencedTDSColumns).flat());
351
364
  }