@finos/legend-query-builder 4.14.68 → 4.14.70
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
- package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderTesting.js +1 -0
- package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts +1 -0
- package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.js +95 -53
- package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts +4 -0
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +172 -108
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +2 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +29 -18
- 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 +13 -4
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +4 -3
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/result/QueryBuilderResultPanel.d.ts +12 -0
- package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/result/QueryBuilderResultPanel.js +60 -8
- package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js +47 -28
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +1 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +34 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
- package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts +11 -0
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +6 -3
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
- package/lib/graph-manager/QueryBuilderConfig.d.ts +4 -0
- package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
- package/lib/graph-manager/QueryBuilderConfig.js +5 -0
- package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryBuilderResultState.d.ts +11 -3
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +47 -4
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts +4 -0
- package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +5 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.js +80 -10
- package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts +24 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +39 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -0
- package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +8 -4
- package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderPropertySearchState.js +204 -114
- package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +8 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js +12 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +8 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +27 -10
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +1 -0
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +6 -2
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +9 -9
- package/src/__lib__/QueryBuilderTesting.ts +1 -0
- package/src/components/explorer/QueryBuilderExplorerPanel.tsx +228 -115
- package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +618 -388
- package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +5 -2
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +78 -44
- package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +63 -10
- package/src/components/filter/QueryBuilderFilterPanel.tsx +4 -2
- package/src/components/result/QueryBuilderResultPanel.tsx +207 -20
- package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +57 -38
- package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +43 -0
- package/src/components/shared/QueryBuilderFilterHelper.ts +8 -0
- package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +13 -3
- package/src/graph-manager/QueryBuilderConfig.ts +6 -0
- package/src/stores/QueryBuilderResultState.ts +64 -10
- package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +5 -0
- package/src/stores/explorer/QueryBuilderExplorerState.ts +112 -8
- package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +46 -0
- package/src/stores/explorer/QueryBuilderPropertySearchState.ts +280 -142
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +8 -1
- package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.ts +15 -2
- package/src/stores/filter/QueryBuilderFilterState.ts +34 -11
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +9 -1
- package/tsconfig.json +1 -0
@@ -61,6 +61,7 @@ import {
|
|
61
61
|
Dialog,
|
62
62
|
CustomSelectorInput,
|
63
63
|
} from '@finos/legend-art';
|
64
|
+
import { getFloatGridColumnCustomHeader } from './QueryBuilderTDSSimpleGridResult.js';
|
64
65
|
|
65
66
|
export const enum QueryBuilderDataGridCustomAggregationFunction {
|
66
67
|
wavg = 'wavg',
|
@@ -87,13 +88,20 @@ const getAggregationTDSColumnCustomizations = (
|
|
87
88
|
filter: 'agDateColumnFilter',
|
88
89
|
allowedAggFuncs: ['count'],
|
89
90
|
};
|
90
|
-
case PRIMITIVE_TYPE.DECIMAL:
|
91
91
|
case PRIMITIVE_TYPE.NUMBER:
|
92
92
|
case PRIMITIVE_TYPE.INTEGER:
|
93
|
+
return {
|
94
|
+
filter: 'agNumberColumnFilter',
|
95
|
+
allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
|
96
|
+
};
|
97
|
+
case PRIMITIVE_TYPE.DECIMAL:
|
93
98
|
case PRIMITIVE_TYPE.FLOAT:
|
94
99
|
return {
|
95
100
|
filter: 'agNumberColumnFilter',
|
96
101
|
allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
|
102
|
+
headerComponentParams: {
|
103
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
104
|
+
},
|
97
105
|
};
|
98
106
|
default:
|
99
107
|
return {
|
@@ -102,42 +110,6 @@ const getAggregationTDSColumnCustomizations = (
|
|
102
110
|
}
|
103
111
|
};
|
104
112
|
|
105
|
-
const getLocalColDefs = (
|
106
|
-
executionResult: TDSExecutionResult,
|
107
|
-
resultState: QueryBuilderResultState,
|
108
|
-
): DataGridColumnDefinition<
|
109
|
-
QueryBuilderTDSRowDataType,
|
110
|
-
QueryBuilderTDSResultCellDataType
|
111
|
-
>[] =>
|
112
|
-
executionResult.result.columns.map((colName) => {
|
113
|
-
const col = {
|
114
|
-
minWidth: 50,
|
115
|
-
sortable: true,
|
116
|
-
resizable: true,
|
117
|
-
field: colName,
|
118
|
-
flex: 1,
|
119
|
-
enablePivot: true,
|
120
|
-
enableRowGroup: true,
|
121
|
-
enableValue: true,
|
122
|
-
...getAggregationTDSColumnCustomizations(executionResult, colName),
|
123
|
-
} as DataGridColumnDefinition;
|
124
|
-
const persistedColumn = resultState.gridConfig?.columns.find(
|
125
|
-
(c) => c.colId === colName,
|
126
|
-
);
|
127
|
-
if (persistedColumn) {
|
128
|
-
if (persistedColumn.width) {
|
129
|
-
col.width = persistedColumn.width;
|
130
|
-
}
|
131
|
-
col.pinned = persistedColumn.pinned ?? null;
|
132
|
-
col.rowGroup = persistedColumn.rowGroup ?? false;
|
133
|
-
col.rowGroupIndex = persistedColumn.rowGroupIndex ?? null;
|
134
|
-
col.aggFunc = persistedColumn.aggFunc ?? null;
|
135
|
-
col.pivot = persistedColumn.pivot ?? false;
|
136
|
-
col.hide = persistedColumn.hide ?? false;
|
137
|
-
}
|
138
|
-
return col;
|
139
|
-
});
|
140
|
-
|
141
113
|
const QueryResultCellRenderer = observer(
|
142
114
|
(params: IQueryRendererParamsWithGridType) => {
|
143
115
|
const resultState = params.resultState;
|
@@ -186,6 +158,47 @@ const QueryResultCellRenderer = observer(
|
|
186
158
|
},
|
187
159
|
);
|
188
160
|
|
161
|
+
const getLocalColDefs = (
|
162
|
+
executionResult: TDSExecutionResult,
|
163
|
+
resultState: QueryBuilderResultState,
|
164
|
+
): DataGridColumnDefinition<
|
165
|
+
QueryBuilderTDSRowDataType,
|
166
|
+
QueryBuilderTDSResultCellDataType
|
167
|
+
>[] =>
|
168
|
+
executionResult.result.columns.map((colName) => {
|
169
|
+
const col = {
|
170
|
+
minWidth: 50,
|
171
|
+
sortable: true,
|
172
|
+
resizable: true,
|
173
|
+
field: colName,
|
174
|
+
flex: 1,
|
175
|
+
enablePivot: true,
|
176
|
+
enableRowGroup: true,
|
177
|
+
enableValue: true,
|
178
|
+
cellRenderer: QueryResultCellRenderer,
|
179
|
+
cellRendererParams: {
|
180
|
+
resultState: resultState,
|
181
|
+
tdsExecutionResult: executionResult,
|
182
|
+
},
|
183
|
+
...getAggregationTDSColumnCustomizations(executionResult, colName),
|
184
|
+
} as DataGridColumnDefinition;
|
185
|
+
const persistedColumn = resultState.gridConfig?.columns.find(
|
186
|
+
(c) => c.colId === colName,
|
187
|
+
);
|
188
|
+
if (persistedColumn) {
|
189
|
+
if (persistedColumn.width) {
|
190
|
+
col.width = persistedColumn.width;
|
191
|
+
}
|
192
|
+
col.pinned = persistedColumn.pinned ?? null;
|
193
|
+
col.rowGroup = persistedColumn.rowGroup ?? false;
|
194
|
+
col.rowGroupIndex = persistedColumn.rowGroupIndex ?? null;
|
195
|
+
col.aggFunc = persistedColumn.aggFunc ?? null;
|
196
|
+
col.pivot = persistedColumn.pivot ?? false;
|
197
|
+
col.hide = persistedColumn.hide ?? false;
|
198
|
+
}
|
199
|
+
return col;
|
200
|
+
});
|
201
|
+
|
189
202
|
const getFilterTDSColumnCustomizations = (
|
190
203
|
result: TDSExecutionResult,
|
191
204
|
columnName: string,
|
@@ -202,11 +215,17 @@ const getFilterTDSColumnCustomizations = (
|
|
202
215
|
};
|
203
216
|
case PRIMITIVE_TYPE.DECIMAL:
|
204
217
|
case PRIMITIVE_TYPE.INTEGER:
|
205
|
-
case PRIMITIVE_TYPE.FLOAT:
|
206
218
|
case PRIMITIVE_TYPE.NUMBER:
|
207
219
|
return {
|
208
220
|
filter: 'agNumberColumnFilter',
|
209
221
|
};
|
222
|
+
case PRIMITIVE_TYPE.FLOAT:
|
223
|
+
return {
|
224
|
+
filter: 'agNumberColumnFilter',
|
225
|
+
headerComponentParams: {
|
226
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
227
|
+
},
|
228
|
+
};
|
210
229
|
default:
|
211
230
|
// we default all other columns to use filter true which defaults to set filters
|
212
231
|
return {
|
@@ -19,6 +19,7 @@ import { observer } from 'mobx-react-lite';
|
|
19
19
|
import type { QueryBuilderState } from '../../../stores/QueryBuilderState.js';
|
20
20
|
import {
|
21
21
|
getTDSRowRankByColumnInAsc,
|
22
|
+
PRIMITIVE_TYPE,
|
22
23
|
TDSExecutionResult,
|
23
24
|
} from '@finos/legend-graph';
|
24
25
|
import {
|
@@ -47,6 +48,47 @@ import type {
|
|
47
48
|
} from '../../../stores/QueryBuilderResultState.js';
|
48
49
|
import { QUERY_BUILDER_TEST_ID } from '../../../__lib__/QueryBuilderTesting.js';
|
49
50
|
|
51
|
+
export const getFloatGridColumnCustomHeader = (
|
52
|
+
columnName: string,
|
53
|
+
): string => ` <div data-testid="query__builder__result__grid__custom-header" class="query-builder__result__values__table__custom-header">
|
54
|
+
<div>${columnName}</div>
|
55
|
+
<div
|
56
|
+
class="query-builder__result__stale-status__icon"
|
57
|
+
title="some values have been rounded using en-us format in this preview grid (defaults to max 4 decimal places)"
|
58
|
+
>
|
59
|
+
<svg
|
60
|
+
stroke="currentColor"
|
61
|
+
fill="currentColor"
|
62
|
+
stroke-width="0"
|
63
|
+
viewBox="0 0 576 512"
|
64
|
+
height="1em"
|
65
|
+
width="1em"
|
66
|
+
xmlns="http://www.w3.org/2000/svg"
|
67
|
+
>
|
68
|
+
<path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path>
|
69
|
+
</svg>
|
70
|
+
</div>
|
71
|
+
</div>`;
|
72
|
+
|
73
|
+
const getTDSColumnCustomizations = (
|
74
|
+
result: TDSExecutionResult,
|
75
|
+
columnName: string,
|
76
|
+
): object => {
|
77
|
+
const columnType = result.builder.columns.find(
|
78
|
+
(col) => col.name === columnName,
|
79
|
+
)?.type;
|
80
|
+
switch (columnType) {
|
81
|
+
case PRIMITIVE_TYPE.FLOAT:
|
82
|
+
return {
|
83
|
+
headerComponentParams: {
|
84
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
85
|
+
},
|
86
|
+
};
|
87
|
+
default:
|
88
|
+
return {};
|
89
|
+
}
|
90
|
+
};
|
91
|
+
|
50
92
|
const QueryResultCellRenderer = observer(
|
51
93
|
(params: IQueryRendererParamsWithGridType) => {
|
52
94
|
const resultState = params.resultState;
|
@@ -368,6 +410,7 @@ export const QueryBuilderTDSSimpleGridResult = observer(
|
|
368
410
|
resizable: true,
|
369
411
|
field: colName,
|
370
412
|
flex: 1,
|
413
|
+
...getTDSColumnCustomizations(executionResult, colName),
|
371
414
|
cellRenderer: QueryResultCellRenderer,
|
372
415
|
cellRendererParams: {
|
373
416
|
resultState: resultState,
|
@@ -28,6 +28,10 @@ import {
|
|
28
28
|
QUERY_BUILDER_VARIABLE_DND_TYPE,
|
29
29
|
type QueryBuilderVariableDragSource,
|
30
30
|
} from './BasicValueSpecificationEditor.js';
|
31
|
+
import {
|
32
|
+
QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE,
|
33
|
+
type QueryBuilderWindowColumnDragSource,
|
34
|
+
} from '../../stores/fetch-structure/tds/window/QueryBuilderWindowState.js';
|
31
35
|
|
32
36
|
export const getDNDItemType = (
|
33
37
|
item: QueryBuilderFilterValueDropTarget,
|
@@ -45,6 +49,10 @@ export const getDNDItemType = (
|
|
45
49
|
case QUERY_BUILDER_VARIABLE_DND_TYPE:
|
46
50
|
return (item as QueryBuilderVariableDragSource).variable.genericType
|
47
51
|
?.value.rawType;
|
52
|
+
case QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE:
|
53
|
+
return (
|
54
|
+
item as QueryBuilderWindowColumnDragSource
|
55
|
+
).columnState.getColumnType();
|
48
56
|
default:
|
49
57
|
return undefined;
|
50
58
|
}
|
@@ -117,7 +117,7 @@ export const QueryBuilderTaggedValueInfoTooltip: React.FC<{
|
|
117
117
|
);
|
118
118
|
};
|
119
119
|
|
120
|
-
const QueryBuilderBaseInfoTooltip: React.FC<{
|
120
|
+
export const QueryBuilderBaseInfoTooltip: React.FC<{
|
121
121
|
title: string;
|
122
122
|
data: {
|
123
123
|
label: string;
|
@@ -133,7 +133,10 @@ const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
133
133
|
const [open, setIsOpen] = useState(false);
|
134
134
|
|
135
135
|
return (
|
136
|
-
<ClickAwayListener
|
136
|
+
<ClickAwayListener
|
137
|
+
onClickAway={() => setIsOpen(false)}
|
138
|
+
mouseEvent="onMouseDown"
|
139
|
+
>
|
137
140
|
<div>
|
138
141
|
<Tooltip
|
139
142
|
arrow={true}
|
@@ -172,7 +175,14 @@ const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
172
175
|
</div>
|
173
176
|
}
|
174
177
|
>
|
175
|
-
<div
|
178
|
+
<div
|
179
|
+
onClick={(event: React.MouseEvent) => {
|
180
|
+
setIsOpen(!open);
|
181
|
+
event.stopPropagation();
|
182
|
+
}}
|
183
|
+
>
|
184
|
+
{children}
|
185
|
+
</div>
|
176
186
|
</Tooltip>
|
177
187
|
</div>
|
178
188
|
</ClickAwayListener>
|
@@ -33,11 +33,17 @@ export class QueryBuilderConfig {
|
|
33
33
|
*/
|
34
34
|
legendAIServiceURL = '';
|
35
35
|
|
36
|
+
/**
|
37
|
+
* This is the URL of the zipkin trace
|
38
|
+
*/
|
39
|
+
zipkinTraceBaseURL = '';
|
40
|
+
|
36
41
|
static readonly serialization = new SerializationFactory(
|
37
42
|
createModelSchema(QueryBuilderConfig, {
|
38
43
|
TEMPORARY__disableQueryBuilderChat: optional(primitive()),
|
39
44
|
TEMPORARY__enableGridEnterpriseMode: optional(primitive()),
|
40
45
|
legendAIServiceURL: optional(primitive()),
|
46
|
+
zipkinTraceBaseURL: optional(primitive()),
|
41
47
|
}),
|
42
48
|
);
|
43
49
|
}
|
@@ -17,10 +17,10 @@
|
|
17
17
|
import { action, flow, makeObservable, observable } from 'mobx';
|
18
18
|
import {
|
19
19
|
type GeneratorFn,
|
20
|
+
type ContentType,
|
20
21
|
assertErrorThrown,
|
21
22
|
LogEvent,
|
22
23
|
guaranteeNonNullable,
|
23
|
-
type ContentType,
|
24
24
|
ActionState,
|
25
25
|
StopWatch,
|
26
26
|
getContentTypeFileExtension,
|
@@ -32,11 +32,13 @@ import {
|
|
32
32
|
type RawLambda,
|
33
33
|
type EXECUTION_SERIALIZATION_FORMAT,
|
34
34
|
type QueryGridConfig,
|
35
|
+
type ExecutionResultWithMetadata,
|
35
36
|
GRAPH_MANAGER_EVENT,
|
36
37
|
buildRawLambdaFromLambdaFunction,
|
37
38
|
reportGraphAnalytics,
|
39
|
+
TDSExecutionResult,
|
40
|
+
V1_ZIPKIN_TRACE_HEADER,
|
38
41
|
} from '@finos/legend-graph';
|
39
|
-
|
40
42
|
import { buildLambdaFunction } from './QueryBuilderValueSpecificationBuilder.js';
|
41
43
|
import {
|
42
44
|
buildExecutionParameterValues,
|
@@ -49,6 +51,7 @@ import { ExecutionPlanState } from './execution-plan/ExecutionPlanState.js';
|
|
49
51
|
import type { DataGridColumnState } from '@finos/legend-lego/data-grid';
|
50
52
|
import { downloadStream } from '@finos/legend-application';
|
51
53
|
import { QueryBuilderDataGridCustomAggregationFunction } from '../components/result/tds/QueryBuilderTDSGridResult.js';
|
54
|
+
import { QueryBuilderTDSState } from './fetch-structure/tds/QueryBuilderTDSState.js';
|
52
55
|
|
53
56
|
export const DEFAULT_LIMIT = 1000;
|
54
57
|
|
@@ -125,10 +128,13 @@ export class QueryBuilderResultState {
|
|
125
128
|
isRunningQuery = false;
|
126
129
|
isGeneratingPlan = false;
|
127
130
|
executionResult?: ExecutionResult | undefined;
|
131
|
+
isExecutionResultOverflowing = false;
|
128
132
|
executionDuration?: number | undefined;
|
133
|
+
executionTraceId?: string;
|
129
134
|
latestRunHashCode?: string | undefined;
|
130
|
-
queryRunPromise: Promise<
|
135
|
+
queryRunPromise: Promise<ExecutionResultWithMetadata> | undefined = undefined;
|
131
136
|
isQueryUsageViewerOpened = false;
|
137
|
+
executionError: Error | string | undefined;
|
132
138
|
|
133
139
|
selectedCells: QueryBuilderTDSResultCellData[];
|
134
140
|
mousedOverCell: QueryBuilderTDSResultCellData | null = null;
|
@@ -140,6 +146,7 @@ export class QueryBuilderResultState {
|
|
140
146
|
constructor(queryBuilderState: QueryBuilderState) {
|
141
147
|
makeObservable(this, {
|
142
148
|
executionResult: observable,
|
149
|
+
executionTraceId: observable,
|
143
150
|
previewLimit: observable,
|
144
151
|
executionDuration: observable,
|
145
152
|
latestRunHashCode: observable,
|
@@ -150,13 +157,16 @@ export class QueryBuilderResultState {
|
|
150
157
|
isRunningQuery: observable,
|
151
158
|
isSelectingCells: observable,
|
152
159
|
isQueryUsageViewerOpened: observable,
|
160
|
+
isExecutionResultOverflowing: observable,
|
153
161
|
gridConfig: observable,
|
154
162
|
wavgAggregationState: observable,
|
163
|
+
executionError: observable,
|
155
164
|
setGridConfig: action,
|
156
165
|
setWavgAggregationState: action,
|
157
166
|
setIsSelectingCells: action,
|
158
167
|
setIsRunningQuery: action,
|
159
168
|
setExecutionResult: action,
|
169
|
+
setExecutionTraceId: action,
|
160
170
|
setExecutionDuration: action,
|
161
171
|
setPreviewLimit: action,
|
162
172
|
addSelectedCell: action,
|
@@ -164,8 +174,10 @@ export class QueryBuilderResultState {
|
|
164
174
|
setMouseOverCell: action,
|
165
175
|
setQueryRunPromise: action,
|
166
176
|
setIsQueryUsageViewerOpened: action,
|
177
|
+
setIsExecutionResultOverflowing: action,
|
167
178
|
handlePreConfiguredGridConfig: action,
|
168
179
|
updatePreviewLimitInConfig: action,
|
180
|
+
setExecutionError: action,
|
169
181
|
exportData: flow,
|
170
182
|
runQuery: flow,
|
171
183
|
cancelQuery: flow,
|
@@ -204,6 +216,10 @@ export class QueryBuilderResultState {
|
|
204
216
|
this.executionResult = val;
|
205
217
|
}
|
206
218
|
|
219
|
+
setExecutionTraceId(val: string): void {
|
220
|
+
this.executionTraceId = val;
|
221
|
+
}
|
222
|
+
|
207
223
|
setExecutionDuration(val: number | undefined): void {
|
208
224
|
this.executionDuration = val;
|
209
225
|
}
|
@@ -224,7 +240,9 @@ export class QueryBuilderResultState {
|
|
224
240
|
this.mousedOverCell = val;
|
225
241
|
}
|
226
242
|
|
227
|
-
setQueryRunPromise(
|
243
|
+
setQueryRunPromise(
|
244
|
+
promise: Promise<ExecutionResultWithMetadata> | undefined,
|
245
|
+
): void {
|
228
246
|
this.queryRunPromise = promise;
|
229
247
|
}
|
230
248
|
|
@@ -232,12 +250,44 @@ export class QueryBuilderResultState {
|
|
232
250
|
this.isQueryUsageViewerOpened = val;
|
233
251
|
}
|
234
252
|
|
253
|
+
setExecutionError(val: Error | string | undefined): void {
|
254
|
+
this.executionError = val;
|
255
|
+
}
|
256
|
+
|
257
|
+
setIsExecutionResultOverflowing(val: boolean): void {
|
258
|
+
this.isExecutionResultOverflowing = val;
|
259
|
+
}
|
260
|
+
|
235
261
|
updatePreviewLimitInConfig(): void {
|
236
262
|
if (this.gridConfig) {
|
237
263
|
this.gridConfig.previewLimit = this.previewLimit;
|
238
264
|
}
|
239
265
|
}
|
240
266
|
|
267
|
+
getExecutionResultLimit = (): number =>
|
268
|
+
Math.min(
|
269
|
+
this.queryBuilderState.fetchStructureState.implementation instanceof
|
270
|
+
QueryBuilderTDSState &&
|
271
|
+
this.queryBuilderState.fetchStructureState.implementation
|
272
|
+
.resultSetModifierState.limit
|
273
|
+
? this.queryBuilderState.fetchStructureState.implementation
|
274
|
+
.resultSetModifierState.limit
|
275
|
+
: Number.MAX_SAFE_INTEGER,
|
276
|
+
this.previewLimit,
|
277
|
+
);
|
278
|
+
|
279
|
+
processExecutionResult = (result: ExecutionResult): void => {
|
280
|
+
this.setIsExecutionResultOverflowing(false);
|
281
|
+
if (result instanceof TDSExecutionResult) {
|
282
|
+
const resultLimit = this.getExecutionResultLimit();
|
283
|
+
if (result.result.rows.length > resultLimit) {
|
284
|
+
this.setIsExecutionResultOverflowing(true);
|
285
|
+
result.result.rows = result.result.rows.slice(0, resultLimit);
|
286
|
+
}
|
287
|
+
}
|
288
|
+
this.setExecutionResult(result);
|
289
|
+
};
|
290
|
+
|
241
291
|
processWeightedColumnPairsMap(
|
242
292
|
config: QueryGridConfig,
|
243
293
|
): Map<string, string> | undefined {
|
@@ -421,7 +471,9 @@ export class QueryBuilderResultState {
|
|
421
471
|
this.queryBuilderState.executionContextState.runtimeValue,
|
422
472
|
`Runtime is required to execute query`,
|
423
473
|
);
|
424
|
-
const query = this.buildExecutionRawLambda(
|
474
|
+
const query = this.buildExecutionRawLambda({
|
475
|
+
withDataOverflowCheck: true,
|
476
|
+
});
|
425
477
|
const parameterValues = buildExecutionParameterValues(
|
426
478
|
this.queryBuilderState.parametersState.parameterStates,
|
427
479
|
this.queryBuilderState.graphManagerState,
|
@@ -444,13 +496,17 @@ export class QueryBuilderResultState {
|
|
444
496
|
{
|
445
497
|
parameterValues,
|
446
498
|
convertUnsafeNumbersToString: true,
|
499
|
+
preservedResponseHeadersList: [V1_ZIPKIN_TRACE_HEADER],
|
447
500
|
},
|
448
501
|
);
|
449
502
|
|
450
503
|
this.setQueryRunPromise(promise);
|
451
|
-
const result = (yield promise) as
|
504
|
+
const result = (yield promise) as ExecutionResultWithMetadata;
|
452
505
|
if (this.queryRunPromise === promise) {
|
453
|
-
this.
|
506
|
+
this.processExecutionResult(result.executionResult);
|
507
|
+
if (result.executionTraceId) {
|
508
|
+
this.setExecutionTraceId(result.executionTraceId);
|
509
|
+
}
|
454
510
|
this.latestRunHashCode = currentHashCode;
|
455
511
|
this.setExecutionDuration(stopWatch.elapsed);
|
456
512
|
|
@@ -479,9 +535,7 @@ export class QueryBuilderResultState {
|
|
479
535
|
LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE),
|
480
536
|
error,
|
481
537
|
);
|
482
|
-
this.
|
483
|
-
error,
|
484
|
-
);
|
538
|
+
this.setExecutionError(error);
|
485
539
|
}
|
486
540
|
} finally {
|
487
541
|
this.setIsRunningQuery(false);
|
@@ -210,4 +210,9 @@ export type LambdaFunctionBuilderOption = {
|
|
210
210
|
* typed in engine. This is still an experimental feature, hence we should only enable this flag when user wants to enable this directly.
|
211
211
|
*/
|
212
212
|
useTypedRelationFunctions?: boolean | undefined;
|
213
|
+
|
214
|
+
/**
|
215
|
+
* Set this flag to `true` when you want to execute a query that exceeds the limit to check for additional data in the database.
|
216
|
+
*/
|
217
|
+
withDataOverflowCheck?: boolean | undefined;
|
213
218
|
};
|
@@ -118,8 +118,10 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
|
|
118
118
|
) {
|
119
119
|
makeObservable(this, {
|
120
120
|
isHighlighting: observable,
|
121
|
+
isOpen: observable,
|
121
122
|
isSelected: observable,
|
122
123
|
setIsHighlighting: action,
|
124
|
+
setIsOpen: action,
|
123
125
|
setIsSelected: action,
|
124
126
|
});
|
125
127
|
|
@@ -136,6 +138,10 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
|
|
136
138
|
this.isSelected = val;
|
137
139
|
}
|
138
140
|
|
141
|
+
setIsOpen(val: boolean | undefined): void {
|
142
|
+
this.isOpen = val;
|
143
|
+
}
|
144
|
+
|
139
145
|
setIsHighlighting(val: boolean | undefined): void {
|
140
146
|
this.isHighlighting = val;
|
141
147
|
}
|
@@ -650,15 +656,18 @@ export class QueryBuilderExplorerPreviewDataState {
|
|
650
656
|
isGeneratingPreviewData = false;
|
651
657
|
propertyName = '(unknown)';
|
652
658
|
previewData?: QueryBuilderPreviewData | undefined;
|
659
|
+
previewDataAbortController?: AbortController | undefined;
|
653
660
|
|
654
661
|
constructor() {
|
655
662
|
makeObservable(this, {
|
656
663
|
previewData: observable.ref,
|
657
664
|
isGeneratingPreviewData: observable,
|
658
665
|
propertyName: observable,
|
666
|
+
previewDataAbortController: observable,
|
659
667
|
setPropertyName: action,
|
660
668
|
setIsGeneratingPreviewData: action,
|
661
669
|
setPreviewData: action,
|
670
|
+
setPreviewDataAbortController: action,
|
662
671
|
});
|
663
672
|
}
|
664
673
|
|
@@ -673,6 +682,10 @@ export class QueryBuilderExplorerPreviewDataState {
|
|
673
682
|
setPreviewData(val: QueryBuilderPreviewData | undefined): void {
|
674
683
|
this.previewData = val;
|
675
684
|
}
|
685
|
+
|
686
|
+
setPreviewDataAbortController(val: AbortController | undefined): void {
|
687
|
+
this.previewDataAbortController = val;
|
688
|
+
}
|
676
689
|
}
|
677
690
|
|
678
691
|
export class QueryBuilderExplorerState {
|
@@ -754,21 +767,99 @@ export class QueryBuilderExplorerState {
|
|
754
767
|
);
|
755
768
|
}
|
756
769
|
|
757
|
-
|
758
|
-
|
759
|
-
|
770
|
+
generateOpenNodeChildren(node: QueryBuilderExplorerTreeNodeData): void {
|
771
|
+
if (
|
772
|
+
node.isOpen &&
|
773
|
+
(node instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
774
|
+
node instanceof QueryBuilderExplorerTreeSubTypeNodeData) &&
|
775
|
+
node.type instanceof Class
|
776
|
+
) {
|
777
|
+
(node instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
778
|
+
? getAllOwnClassProperties(node.type)
|
779
|
+
: getAllClassProperties(node.type).concat(
|
780
|
+
getAllClassDerivedProperties(node.type),
|
781
|
+
)
|
782
|
+
).forEach((property) => {
|
783
|
+
const propertyTreeNodeData = getQueryBuilderPropertyNodeData(
|
784
|
+
property,
|
785
|
+
node,
|
786
|
+
guaranteeNonNullable(this.mappingModelCoverageAnalysisResult),
|
787
|
+
);
|
788
|
+
if (propertyTreeNodeData) {
|
789
|
+
this.nonNullableTreeData.nodes.set(
|
790
|
+
propertyTreeNodeData.id,
|
791
|
+
propertyTreeNodeData,
|
792
|
+
);
|
793
|
+
}
|
794
|
+
});
|
795
|
+
node.type._subclasses.forEach((subclass) => {
|
796
|
+
const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(
|
797
|
+
subclass,
|
798
|
+
node,
|
799
|
+
guaranteeNonNullable(this.mappingModelCoverageAnalysisResult),
|
800
|
+
);
|
801
|
+
this.nonNullableTreeData.nodes.set(
|
802
|
+
subTypeTreeNodeData.id,
|
803
|
+
subTypeTreeNodeData,
|
804
|
+
);
|
805
|
+
});
|
806
|
+
this.refreshTree();
|
807
|
+
}
|
808
|
+
}
|
809
|
+
|
810
|
+
highlightTreeNode(nodeId: string): void {
|
811
|
+
// If the node doesn't yet exist in the explorer tree,
|
812
|
+
// we need to open all the parent nodes of the node and
|
813
|
+
// generate their children.
|
814
|
+
if (this.nonNullableTreeData.nodes.get(nodeId) === undefined) {
|
815
|
+
const parentNodeIdElements: string[][] = nodeId
|
816
|
+
.split('@')
|
817
|
+
.map((subpath) => subpath.split('.'));
|
818
|
+
// remove last element of final subpath, as it is the node id and not a parent
|
819
|
+
if (
|
820
|
+
parentNodeIdElements.length > 0 &&
|
821
|
+
parentNodeIdElements[parentNodeIdElements.length - 1] !== undefined
|
822
|
+
) {
|
823
|
+
parentNodeIdElements[parentNodeIdElements.length - 1]!.pop();
|
824
|
+
}
|
825
|
+
|
826
|
+
let currentNodeId = '';
|
827
|
+
|
828
|
+
parentNodeIdElements.forEach((subpath) => {
|
829
|
+
subpath.forEach((element, index) => {
|
830
|
+
currentNodeId += `${index > 0 ? '.' : ''}${element}`;
|
831
|
+
const currentNode = this.nonNullableTreeData.nodes.get(currentNodeId);
|
832
|
+
if (currentNode) {
|
833
|
+
currentNode.setIsOpen(true);
|
834
|
+
this.generateOpenNodeChildren(currentNode);
|
835
|
+
}
|
836
|
+
});
|
837
|
+
currentNodeId += '@';
|
838
|
+
});
|
839
|
+
}
|
840
|
+
|
841
|
+
// All parent nodes should be created now, so we can get the node to highlight.
|
842
|
+
const nodeToHighlight = this.nonNullableTreeData.nodes.get(nodeId);
|
843
|
+
|
844
|
+
// If we didn't need to open and create the parent nodes above, we will
|
845
|
+
// open the parent nodes here in case they are closed. Then, we will highlight
|
846
|
+
// and scroll to the node.
|
847
|
+
if (
|
848
|
+
nodeToHighlight instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
849
|
+
nodeToHighlight instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
850
|
+
) {
|
760
851
|
let nodeToOpen: QueryBuilderExplorerTreeNodeData | null =
|
761
|
-
this.
|
852
|
+
this.nonNullableTreeData.nodes.get(nodeToHighlight.parentId) ?? null;
|
762
853
|
while (nodeToOpen !== null) {
|
763
854
|
if (!nodeToOpen.isOpen) {
|
764
|
-
nodeToOpen.
|
855
|
+
nodeToOpen.setIsOpen(true);
|
765
856
|
}
|
766
857
|
nodeToOpen =
|
767
|
-
nodeToOpen instanceof QueryBuilderExplorerTreePropertyNodeData
|
768
|
-
|
858
|
+
nodeToOpen instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
859
|
+
nodeToOpen instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
860
|
+
? (this.nonNullableTreeData.nodes.get(nodeToOpen.parentId) ?? null)
|
769
861
|
: null;
|
770
862
|
}
|
771
|
-
this.refreshTree();
|
772
863
|
nodeToHighlight.setIsHighlighting(true);
|
773
864
|
// scrollIntoView must be called in a setTimeout because it must happen after
|
774
865
|
// the tree nodes are recursively opened and the tree is refreshed.
|
@@ -859,6 +950,7 @@ export class QueryBuilderExplorerState {
|
|
859
950
|
this,
|
860
951
|
);
|
861
952
|
const propertyType = node.property.genericType.value.rawType;
|
953
|
+
this.previewDataState.setPreviewDataAbortController(new AbortController());
|
862
954
|
try {
|
863
955
|
switch (propertyType.path) {
|
864
956
|
case PRIMITIVE_TYPE.NUMBER:
|
@@ -874,6 +966,10 @@ export class QueryBuilderExplorerState {
|
|
874
966
|
this.queryBuilderState.executionContextState.mapping,
|
875
967
|
runtime,
|
876
968
|
this.queryBuilderState.graphManagerState.graph,
|
969
|
+
{
|
970
|
+
abortController:
|
971
|
+
this.previewDataState.previewDataAbortController,
|
972
|
+
},
|
877
973
|
)) as ExecutionResult;
|
878
974
|
assertType(
|
879
975
|
previewResult,
|
@@ -911,6 +1007,10 @@ export class QueryBuilderExplorerState {
|
|
911
1007
|
this.queryBuilderState.executionContextState.mapping,
|
912
1008
|
runtime,
|
913
1009
|
this.queryBuilderState.graphManagerState.graph,
|
1010
|
+
{
|
1011
|
+
abortController:
|
1012
|
+
this.previewDataState.previewDataAbortController,
|
1013
|
+
},
|
914
1014
|
)) as ExecutionResult;
|
915
1015
|
assertType(
|
916
1016
|
previewResult,
|
@@ -929,12 +1029,16 @@ export class QueryBuilderExplorerState {
|
|
929
1029
|
}
|
930
1030
|
} catch (error) {
|
931
1031
|
assertErrorThrown(error);
|
1032
|
+
if (error.name === 'AbortError') {
|
1033
|
+
return;
|
1034
|
+
}
|
932
1035
|
this.queryBuilderState.applicationStore.notificationService.notifyWarning(
|
933
1036
|
`Can't preview data for property '${node.property.name}'. Error: ${error.message}`,
|
934
1037
|
);
|
935
1038
|
this.previewDataState.setPreviewData(undefined);
|
936
1039
|
} finally {
|
937
1040
|
this.previewDataState.setIsGeneratingPreviewData(false);
|
1041
|
+
this.previewDataState.setPreviewDataAbortController(undefined);
|
938
1042
|
}
|
939
1043
|
}
|
940
1044
|
}
|