@finos/legend-query-builder 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }