@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.
- package/lib/components/QueryBuilder.js +1 -1
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderResultPanel.js +15 -5
- package/lib/components/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +19 -17
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +34 -31
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +3 -3
- package/lib/stores/QueryBuilderResultState.d.ts +7 -3
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +14 -20
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts +3 -0
- package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js.map +1 -1
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts +10 -1
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +36 -1
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts +6 -0
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +21 -2
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts +1 -0
- package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js +10 -1
- package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js.map +1 -1
- package/package.json +10 -10
- package/src/components/QueryBuilder.tsx +1 -1
- package/src/components/QueryBuilderResultPanel.tsx +30 -17
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +128 -126
- package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +262 -256
- package/src/stores/QueryBuilderResultState.ts +28 -33
- package/src/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.ts +5 -0
- package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.ts +44 -0
- package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +28 -0
- 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
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
}
|