@finos/legend-query-builder 4.0.8 → 4.0.10
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/__lib__/QueryBuilderColorTheme.js +1 -1
- package/lib/__lib__/QueryBuilderColorTheme.js.map +1 -1
- package/lib/__lib__/QueryBuilderDocumentation.js +1 -1
- package/lib/__lib__/QueryBuilderDocumentation.js.map +1 -1
- package/lib/__lib__/QueryBuilderEvent.js +3 -3
- package/lib/__lib__/QueryBuilderEvent.js.map +1 -1
- package/lib/__lib__/QueryBuilderSetting.js +1 -1
- package/lib/__lib__/QueryBuilderSetting.js.map +1 -1
- package/lib/__lib__/QueryBuilderTesting.js +1 -1
- package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
- package/lib/components/QueryBuilderComponentElement.js +1 -1
- package/lib/components/QueryBuilderComponentElement.js.map +1 -1
- package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderResultPanel.js +210 -69
- package/lib/components/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js +1 -2
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.js +3 -3
- package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js +3 -3
- package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +60 -21
- 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 +10 -2
- 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 +2 -2
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts +4 -0
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +69 -31
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/shared/CustomDatePicker.js +1 -1
- package/lib/components/shared/CustomDatePicker.js.map +1 -1
- package/lib/graph/QueryBuilderMetaModelConst.js +3 -3
- package/lib/graph/QueryBuilderMetaModelConst.js.map +1 -1
- package/lib/graph-manager/QueryBuilderConst.js +1 -1
- package/lib/graph-manager/QueryBuilderConst.js.map +1 -1
- package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.d.ts.map +1 -1
- package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.js +4 -4
- package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.js.map +1 -1
- package/lib/index.css +17 -1
- package/lib/index.css.map +1 -1
- package/lib/package.json +7 -7
- package/lib/stores/QueryBuilderChangeDetectionState.js +1 -1
- package/lib/stores/QueryBuilderChangeDetectionState.js.map +1 -1
- package/lib/stores/QueryBuilderCommand.js +1 -1
- package/lib/stores/QueryBuilderCommand.js.map +1 -1
- package/lib/stores/QueryBuilderConfig.js +2 -2
- package/lib/stores/QueryBuilderConfig.js.map +1 -1
- package/lib/stores/QueryBuilderGroupOperationHelper.js +1 -1
- package/lib/stores/QueryBuilderGroupOperationHelper.js.map +1 -1
- package/lib/stores/QueryBuilderResultState.d.ts +19 -0
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +48 -1
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.js +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
- package/lib/stores/QueryBuilderTextEditorState.js +1 -1
- package/lib/stores/QueryBuilderTextEditorState.js.map +1 -1
- package/lib/stores/execution-plan/ExecutionPlanState.js +1 -1
- package/lib/stores/execution-plan/ExecutionPlanState.js.map +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.js +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
- package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js +1 -1
- package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js.map +1 -1
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +2 -2
- package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js +1 -1
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.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 +2 -2
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/shared/LambdaParameterState.d.ts.map +1 -1
- package/lib/stores/shared/LambdaParameterState.js +2 -2
- package/lib/stores/shared/LambdaParameterState.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +5 -2
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +30 -40
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +15 -15
- package/src/components/QueryBuilderResultPanel.tsx +358 -93
- package/src/components/explorer/QueryBuilderExplorerPanel.tsx +10 -14
- package/src/components/fetch-structure/QueryBuilderFetchStructurePanel.tsx +6 -4
- package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +103 -14
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +18 -1
- package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +12 -10
- package/src/components/filter/QueryBuilderFilterPanel.tsx +134 -42
- package/src/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.ts +4 -5
- package/src/stores/QueryBuilderResultState.ts +82 -0
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +1 -0
- package/src/stores/shared/LambdaParameterState.ts +1 -0
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +80 -57
@@ -66,10 +66,9 @@ import {
|
|
66
66
|
isBoolean,
|
67
67
|
type PlainObject,
|
68
68
|
prettyDuration,
|
69
|
-
prettyCONSTName,
|
70
69
|
filterByType,
|
71
70
|
} from '@finos/legend-shared';
|
72
|
-
import {
|
71
|
+
import { forwardRef, useState } from 'react';
|
73
72
|
import {
|
74
73
|
QueryBuilderDerivationProjectionColumnState,
|
75
74
|
QueryBuilderProjectionColumnState,
|
@@ -97,13 +96,22 @@ import { PARAMETER_SUBMIT_ACTION } from '../stores/shared/LambdaParameterState.j
|
|
97
96
|
import { QUERY_BUILDER_TEST_ID } from '../__lib__/QueryBuilderTesting.js';
|
98
97
|
import {
|
99
98
|
DataGrid,
|
100
|
-
type
|
99
|
+
type DataGridCellRendererParams,
|
101
100
|
} from '@finos/legend-lego/data-grid';
|
102
101
|
import {
|
103
102
|
CODE_EDITOR_LANGUAGE,
|
104
103
|
CodeEditor,
|
105
104
|
} from '@finos/legend-lego/code-editor';
|
106
105
|
import { ExecutionPlanViewer } from './execution-plan/ExecutionPlanViewer.js';
|
106
|
+
import type {
|
107
|
+
QueryBuilderTDSResultCellCoordinate,
|
108
|
+
QueryBuilderResultState,
|
109
|
+
QueryBuilderTDSResultCellData,
|
110
|
+
} from '../stores/QueryBuilderResultState.js';
|
111
|
+
import {
|
112
|
+
QueryBuilderPostFilterOperator_IsEmpty,
|
113
|
+
QueryBuilderPostFilterOperator_IsNotEmpty,
|
114
|
+
} from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js';
|
107
115
|
|
108
116
|
export const tryToFormatSql = (sql: string): string => {
|
109
117
|
try {
|
@@ -118,7 +126,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
118
126
|
forwardRef<
|
119
127
|
HTMLDivElement,
|
120
128
|
{
|
121
|
-
event:
|
129
|
+
event: QueryBuilderTDSResultCellData | null;
|
122
130
|
tdsState: QueryBuilderTDSState;
|
123
131
|
}
|
124
132
|
>(function QueryBuilderResultContextMenu(props, ref) {
|
@@ -126,20 +134,26 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
126
134
|
const applicationStore = useApplicationStore();
|
127
135
|
const postFilterEqualOperator = new QueryBuilderPostFilterOperator_Equal();
|
128
136
|
const postFilterInOperator = new QueryBuilderPostFilterOperator_In();
|
137
|
+
const postFilterEmptyOperator =
|
138
|
+
new QueryBuilderPostFilterOperator_IsEmpty();
|
139
|
+
const postFilterNotEmptyOperator =
|
140
|
+
new QueryBuilderPostFilterOperator_IsNotEmpty();
|
141
|
+
|
129
142
|
const postFilterNotEqualOperator =
|
130
143
|
new QueryBuilderPostFilterOperator_NotEqual();
|
131
144
|
const postFilterNotInOperator = new QueryBuilderPostFilterOperator_NotIn();
|
132
145
|
const postFilterState = tdsState.postFilterState;
|
133
|
-
|
134
|
-
|
146
|
+
|
147
|
+
const projectionColumnState = tdsState.projectionColumns
|
148
|
+
.filter((c) => c.columnName === event?.columnName)
|
135
149
|
.concat(
|
136
150
|
tdsState.aggregationState.columns
|
137
|
-
.filter((c) => c.columnName === event
|
151
|
+
.filter((c) => c.columnName === event?.columnName)
|
138
152
|
.map((ag) => ag.projectionColumnState),
|
139
153
|
)[0];
|
140
|
-
|
141
154
|
const getExistingPostFilterNode = (
|
142
155
|
operators: QueryBuilderPostFilterOperator[],
|
156
|
+
projectionColumnName: string | undefined,
|
143
157
|
): QueryBuilderPostFilterTreeNodeData | undefined =>
|
144
158
|
Array.from(postFilterState.nodes.values())
|
145
159
|
.filter(
|
@@ -151,7 +165,8 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
151
165
|
.filter(
|
152
166
|
(n) =>
|
153
167
|
(n as QueryBuilderPostFilterTreeConditionNodeData).condition
|
154
|
-
.columnState.columnName ===
|
168
|
+
.columnState.columnName ===
|
169
|
+
(projectionColumnName ?? projectionColumnState?.columnName) &&
|
155
170
|
operators
|
156
171
|
.map((op) => op.getLabel())
|
157
172
|
.includes(
|
@@ -163,8 +178,9 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
163
178
|
|
164
179
|
const updateFilterConditionValue = (
|
165
180
|
conditionValue: InstanceValue,
|
181
|
+
cellData: QueryBuilderTDSResultCellData,
|
166
182
|
): void => {
|
167
|
-
if (
|
183
|
+
if (cellData.value) {
|
168
184
|
instanceValue_setValue(
|
169
185
|
conditionValue,
|
170
186
|
conditionValue instanceof EnumValueInstanceValue
|
@@ -173,10 +189,10 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
173
189
|
(
|
174
190
|
conditionValue.genericType?.ownerReference
|
175
191
|
.value as Enumeration
|
176
|
-
).values.filter((v) => v.name ===
|
192
|
+
).values.filter((v) => v.name === cellData.value)[0],
|
177
193
|
),
|
178
194
|
)
|
179
|
-
:
|
195
|
+
: cellData.value,
|
180
196
|
0,
|
181
197
|
tdsState.queryBuilderState.observerContext,
|
182
198
|
);
|
@@ -185,15 +201,28 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
185
201
|
|
186
202
|
const generateNewPostFilterConditionNodeData = async (
|
187
203
|
operator: QueryBuilderPostFilterOperator,
|
204
|
+
cellData: QueryBuilderTDSResultCellData,
|
188
205
|
): Promise<void> => {
|
189
|
-
|
190
|
-
|
191
|
-
|
206
|
+
let postFilterConditionState: PostFilterConditionState;
|
207
|
+
try {
|
208
|
+
const possibleProjectionColumnState = cellData.columnName
|
209
|
+
? tdsState.projectionColumns
|
210
|
+
.filter((c) => c.columnName === cellData.columnName)
|
211
|
+
.concat(
|
212
|
+
tdsState.aggregationState.columns
|
213
|
+
.filter((c) => c.columnName === cellData.columnName)
|
214
|
+
.map((ag) => ag.projectionColumnState),
|
215
|
+
)[0]
|
216
|
+
: projectionColumnState;
|
217
|
+
|
218
|
+
if (possibleProjectionColumnState) {
|
219
|
+
postFilterConditionState = new PostFilterConditionState(
|
192
220
|
postFilterState,
|
193
|
-
|
221
|
+
possibleProjectionColumnState,
|
194
222
|
undefined,
|
195
223
|
operator,
|
196
224
|
);
|
225
|
+
|
197
226
|
if (
|
198
227
|
projectionColumnState instanceof
|
199
228
|
QueryBuilderDerivationProjectionColumnState
|
@@ -202,13 +231,16 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
202
231
|
projectionColumnState.fetchDerivationLambdaReturnType(),
|
203
232
|
);
|
204
233
|
}
|
234
|
+
|
205
235
|
const defaultFilterConditionValue =
|
206
236
|
postFilterConditionState.operator.getDefaultFilterConditionValue(
|
207
237
|
postFilterConditionState,
|
208
238
|
);
|
239
|
+
|
209
240
|
postFilterConditionState.setValue(defaultFilterConditionValue);
|
210
241
|
updateFilterConditionValue(
|
211
242
|
defaultFilterConditionValue as InstanceValue,
|
243
|
+
cellData,
|
212
244
|
);
|
213
245
|
postFilterState.addNodeFromNode(
|
214
246
|
new QueryBuilderPostFilterTreeConditionNodeData(
|
@@ -217,41 +249,56 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
217
249
|
),
|
218
250
|
undefined,
|
219
251
|
);
|
220
|
-
} catch (error) {
|
221
|
-
assertErrorThrown(error);
|
222
|
-
applicationStore.notificationService.notifyWarning(error.message);
|
223
|
-
return;
|
224
252
|
}
|
253
|
+
} catch (error) {
|
254
|
+
assertErrorThrown(error);
|
255
|
+
applicationStore.notificationService.notifyWarning(error.message);
|
256
|
+
return;
|
225
257
|
}
|
226
258
|
};
|
227
259
|
|
228
260
|
const updateExistingPostFilterConditionNodeData = (
|
229
261
|
existingPostFilterNode: QueryBuilderPostFilterTreeNodeData,
|
230
262
|
isFilterBy: boolean,
|
263
|
+
cellData: QueryBuilderTDSResultCellData,
|
264
|
+
operator: QueryBuilderPostFilterOperator,
|
231
265
|
): void => {
|
266
|
+
if (
|
267
|
+
operator === postFilterEmptyOperator ||
|
268
|
+
operator === postFilterNotEmptyOperator
|
269
|
+
) {
|
270
|
+
const conditionState = (
|
271
|
+
existingPostFilterNode as QueryBuilderPostFilterTreeConditionNodeData
|
272
|
+
).condition;
|
273
|
+
if (conditionState.operator.getLabel() !== operator.getLabel()) {
|
274
|
+
conditionState.changeOperator(
|
275
|
+
isFilterBy ? postFilterEmptyOperator : postFilterNotEmptyOperator,
|
276
|
+
);
|
277
|
+
}
|
278
|
+
return;
|
279
|
+
}
|
232
280
|
const conditionState = (
|
233
281
|
existingPostFilterNode as QueryBuilderPostFilterTreeConditionNodeData
|
234
282
|
).condition;
|
235
|
-
|
236
|
-
|
237
|
-
(isFilterBy
|
238
|
-
? postFilterEqualOperator
|
239
|
-
: postFilterNotEqualOperator
|
240
|
-
).getLabel()
|
241
|
-
) {
|
283
|
+
|
284
|
+
if (conditionState.operator.getLabel() === operator.getLabel()) {
|
242
285
|
const doesValueAlreadyExist =
|
243
286
|
conditionState.value instanceof InstanceValue &&
|
244
287
|
(conditionState.value instanceof EnumValueInstanceValue
|
245
288
|
? conditionState.value.values.map((ef) => ef.value.name)
|
246
289
|
: conditionState.value.values
|
247
|
-
).includes(
|
290
|
+
).includes(cellData.value);
|
291
|
+
|
248
292
|
if (!doesValueAlreadyExist) {
|
249
293
|
const currentValueSpecificaton = conditionState.value;
|
250
294
|
const newValueSpecification =
|
251
295
|
conditionState.operator.getDefaultFilterConditionValue(
|
252
296
|
conditionState,
|
253
297
|
);
|
254
|
-
updateFilterConditionValue(
|
298
|
+
updateFilterConditionValue(
|
299
|
+
newValueSpecification as InstanceValue,
|
300
|
+
cellData,
|
301
|
+
);
|
255
302
|
conditionState.changeOperator(
|
256
303
|
isFilterBy ? postFilterInOperator : postFilterNotInOperator,
|
257
304
|
);
|
@@ -272,12 +319,16 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
272
319
|
: (v as InstanceValue).values,
|
273
320
|
)
|
274
321
|
.flat()
|
275
|
-
.includes(event
|
322
|
+
.includes(cellData.value ?? event?.value);
|
323
|
+
|
276
324
|
if (!doesValueAlreadyExist) {
|
277
325
|
const newValueSpecification = (
|
278
326
|
isFilterBy ? postFilterEqualOperator : postFilterNotEqualOperator
|
279
327
|
).getDefaultFilterConditionValue(conditionState);
|
280
|
-
updateFilterConditionValue(
|
328
|
+
updateFilterConditionValue(
|
329
|
+
newValueSpecification as InstanceValue,
|
330
|
+
cellData,
|
331
|
+
);
|
281
332
|
instanceValue_setValues(
|
282
333
|
conditionState.value as InstanceValue,
|
283
334
|
[
|
@@ -290,32 +341,76 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
290
341
|
}
|
291
342
|
};
|
292
343
|
|
293
|
-
const
|
344
|
+
const getFilterOperator = (
|
345
|
+
isFilterBy: boolean,
|
346
|
+
cellData: QueryBuilderTDSResultCellData,
|
347
|
+
): QueryBuilderPostFilterOperator => {
|
348
|
+
if (isFilterBy === true) {
|
349
|
+
if (cellData.value === null) {
|
350
|
+
return postFilterEmptyOperator;
|
351
|
+
} else {
|
352
|
+
return postFilterEqualOperator;
|
353
|
+
}
|
354
|
+
} else {
|
355
|
+
if (cellData.value === null) {
|
356
|
+
return postFilterNotEmptyOperator;
|
357
|
+
} else {
|
358
|
+
return postFilterNotEqualOperator;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
};
|
362
|
+
|
363
|
+
const filterByOrOutValue = (
|
364
|
+
isFilterBy: boolean,
|
365
|
+
cellData: QueryBuilderTDSResultCellData,
|
366
|
+
): void => {
|
294
367
|
tdsState.setShowPostFilterPanel(true);
|
368
|
+
|
369
|
+
const operator = getFilterOperator(isFilterBy, cellData);
|
370
|
+
|
295
371
|
const existingPostFilterNode = getExistingPostFilterNode(
|
296
|
-
|
372
|
+
cellData.value === null
|
373
|
+
? [postFilterEmptyOperator, postFilterNotEmptyOperator]
|
374
|
+
: isFilterBy
|
297
375
|
? [postFilterEqualOperator, postFilterInOperator]
|
298
376
|
: [postFilterNotEqualOperator, postFilterNotInOperator],
|
377
|
+
cellData.columnName,
|
299
378
|
);
|
379
|
+
|
300
380
|
existingPostFilterNode === undefined
|
301
|
-
? generateNewPostFilterConditionNodeData(
|
302
|
-
|
303
|
-
)
|
381
|
+
? generateNewPostFilterConditionNodeData(operator, cellData).catch(
|
382
|
+
applicationStore.alertUnhandledError,
|
383
|
+
)
|
304
384
|
: updateExistingPostFilterConditionNodeData(
|
305
385
|
existingPostFilterNode,
|
306
386
|
isFilterBy,
|
387
|
+
cellData,
|
388
|
+
operator,
|
307
389
|
);
|
308
390
|
};
|
309
391
|
|
392
|
+
const filterByOrOutValues = (isFilterBy: boolean): void => {
|
393
|
+
tdsState.queryBuilderState.resultState.selectedCells.forEach(
|
394
|
+
(cellData) => {
|
395
|
+
filterByOrOutValue(isFilterBy, cellData);
|
396
|
+
},
|
397
|
+
);
|
398
|
+
};
|
399
|
+
|
310
400
|
const handleCopyCellValue = applicationStore.guardUnhandledError(() =>
|
311
401
|
applicationStore.clipboardService.copyTextToClipboard(
|
312
|
-
event
|
402
|
+
event?.value?.toString() ?? '',
|
313
403
|
),
|
314
404
|
);
|
315
405
|
|
316
406
|
const handleCopyRowValue = applicationStore.guardUnhandledError(() =>
|
317
407
|
applicationStore.clipboardService.copyTextToClipboard(
|
318
|
-
|
408
|
+
tdsState.queryBuilderState.resultState
|
409
|
+
.findRowFromRowIndex(
|
410
|
+
tdsState.queryBuilderState.resultState.selectedCells[0]?.coordinates
|
411
|
+
.rowIndex ?? 0,
|
412
|
+
)
|
413
|
+
.toString(),
|
319
414
|
),
|
320
415
|
);
|
321
416
|
|
@@ -324,7 +419,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
324
419
|
<MenuContentItem
|
325
420
|
disabled={!projectionColumnState}
|
326
421
|
onClick={(): void => {
|
327
|
-
|
422
|
+
filterByOrOutValues(true);
|
328
423
|
}}
|
329
424
|
>
|
330
425
|
Filter By
|
@@ -332,7 +427,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
332
427
|
<MenuContentItem
|
333
428
|
disabled={!projectionColumnState}
|
334
429
|
onClick={(): void => {
|
335
|
-
|
430
|
+
filterByOrOutValues(false);
|
336
431
|
}}
|
337
432
|
>
|
338
433
|
Filter Out
|
@@ -349,18 +444,201 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
349
444
|
}),
|
350
445
|
);
|
351
446
|
|
447
|
+
type IQueryRendererParamsWithGridType = DataGridCellRendererParams & {
|
448
|
+
resultState: QueryBuilderResultState;
|
449
|
+
tdsExecutionResult: TDSExecutionResult;
|
450
|
+
};
|
451
|
+
|
452
|
+
const QueryResultCellRenderer = observer(
|
453
|
+
(params: IQueryRendererParamsWithGridType) => {
|
454
|
+
const resultState = params.resultState;
|
455
|
+
const tdsExecutionResult = params.tdsExecutionResult;
|
456
|
+
|
457
|
+
const cellValue = params.value as string;
|
458
|
+
const columnName = params.column?.getColId() ?? '';
|
459
|
+
|
460
|
+
const findCoordinatesFromResultValue = (
|
461
|
+
colId: string,
|
462
|
+
rowNumber: number,
|
463
|
+
): QueryBuilderTDSResultCellCoordinate => {
|
464
|
+
const colIndex = tdsExecutionResult.result.columns.findIndex(
|
465
|
+
(col) => col === colId,
|
466
|
+
);
|
467
|
+
|
468
|
+
return { rowIndex: rowNumber, colIndex: colIndex };
|
469
|
+
};
|
470
|
+
|
471
|
+
const currentCellCoordinates = findCoordinatesFromResultValue(
|
472
|
+
columnName,
|
473
|
+
params.rowIndex,
|
474
|
+
);
|
475
|
+
|
476
|
+
const cellInFilteredResults = resultState.selectedCells.some(
|
477
|
+
(result) =>
|
478
|
+
result.coordinates.colIndex === currentCellCoordinates.colIndex &&
|
479
|
+
result.coordinates.rowIndex === currentCellCoordinates.rowIndex,
|
480
|
+
);
|
481
|
+
|
482
|
+
const mouseDown: React.MouseEventHandler = (event) => {
|
483
|
+
event.preventDefault();
|
484
|
+
|
485
|
+
if (event.shiftKey) {
|
486
|
+
const coordinates = findCoordinatesFromResultValue(
|
487
|
+
columnName,
|
488
|
+
params.rowIndex,
|
489
|
+
);
|
490
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
491
|
+
coordinates.rowIndex,
|
492
|
+
coordinates.colIndex,
|
493
|
+
]);
|
494
|
+
resultState.addCellData({
|
495
|
+
value: actualValue,
|
496
|
+
columnName: columnName,
|
497
|
+
coordinates: coordinates,
|
498
|
+
});
|
499
|
+
return;
|
500
|
+
}
|
501
|
+
|
502
|
+
if (event.button === 0) {
|
503
|
+
resultState.setIsSelectingCells(true);
|
504
|
+
resultState.setSelectedCells([]);
|
505
|
+
const coordinates = findCoordinatesFromResultValue(
|
506
|
+
columnName,
|
507
|
+
params.rowIndex,
|
508
|
+
);
|
509
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
510
|
+
coordinates.rowIndex,
|
511
|
+
coordinates.colIndex,
|
512
|
+
]);
|
513
|
+
|
514
|
+
const rowNode = params.api.getRowNode(params.rowIndex.toString());
|
515
|
+
|
516
|
+
if (rowNode) {
|
517
|
+
params.api.refreshCells({
|
518
|
+
force: true,
|
519
|
+
columns: [columnName],
|
520
|
+
rowNodes: [rowNode],
|
521
|
+
});
|
522
|
+
}
|
523
|
+
resultState.setSelectedCells([
|
524
|
+
{
|
525
|
+
value: actualValue,
|
526
|
+
columnName: columnName,
|
527
|
+
coordinates: coordinates,
|
528
|
+
},
|
529
|
+
]);
|
530
|
+
}
|
531
|
+
};
|
532
|
+
const mouseUp: React.MouseEventHandler = (event) => {
|
533
|
+
resultState.setIsSelectingCells(false);
|
534
|
+
};
|
535
|
+
|
536
|
+
const mouseOver: React.MouseEventHandler = (event) => {
|
537
|
+
if (resultState.isSelectingCells) {
|
538
|
+
if (resultState.selectedCells.length < 1) {
|
539
|
+
return;
|
540
|
+
}
|
541
|
+
const results = resultState.selectedCells[0];
|
542
|
+
if (!results) {
|
543
|
+
return;
|
544
|
+
}
|
545
|
+
|
546
|
+
const firstCorner = results.coordinates;
|
547
|
+
const secondCorner = findCoordinatesFromResultValue(
|
548
|
+
columnName,
|
549
|
+
params.rowIndex,
|
550
|
+
);
|
551
|
+
|
552
|
+
resultState.setSelectedCells([results]);
|
553
|
+
|
554
|
+
const minRow = Math.min(firstCorner.rowIndex, secondCorner.rowIndex);
|
555
|
+
const minCol = Math.min(firstCorner.colIndex, secondCorner.colIndex);
|
556
|
+
const maxRow = Math.max(firstCorner.rowIndex, secondCorner.rowIndex);
|
557
|
+
const maxCol = Math.max(firstCorner.colIndex, secondCorner.colIndex);
|
558
|
+
|
559
|
+
for (let x = minRow; x <= maxRow; x++) {
|
560
|
+
for (let y = minCol; y <= maxCol; y++) {
|
561
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
562
|
+
x,
|
563
|
+
y,
|
564
|
+
]);
|
565
|
+
|
566
|
+
const valueAndColumnId = {
|
567
|
+
value: actualValue,
|
568
|
+
columnName: resultState.findColumnFromCoordinates(y),
|
569
|
+
coordinates: {
|
570
|
+
rowIndex: x,
|
571
|
+
colIndex: y,
|
572
|
+
},
|
573
|
+
} as QueryBuilderTDSResultCellData;
|
574
|
+
|
575
|
+
if (
|
576
|
+
!resultState.selectedCells.find(
|
577
|
+
(result) =>
|
578
|
+
result.coordinates.colIndex === y &&
|
579
|
+
result.coordinates.rowIndex === x,
|
580
|
+
)
|
581
|
+
) {
|
582
|
+
resultState.addCellData(valueAndColumnId);
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
588
|
+
resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
|
589
|
+
};
|
590
|
+
|
591
|
+
const fetchStructureImplementation =
|
592
|
+
resultState.queryBuilderState.fetchStructureState.implementation;
|
593
|
+
|
594
|
+
return (
|
595
|
+
<ContextMenu
|
596
|
+
content={
|
597
|
+
// NOTE: we only support this functionality for grid result with a projection fetch-structure
|
598
|
+
fetchStructureImplementation instanceof QueryBuilderTDSState ? (
|
599
|
+
<QueryBuilderGridResultContextMenu
|
600
|
+
event={resultState.mousedOverCell}
|
601
|
+
tdsState={fetchStructureImplementation}
|
602
|
+
/>
|
603
|
+
) : null
|
604
|
+
}
|
605
|
+
disabled={
|
606
|
+
!(
|
607
|
+
resultState.queryBuilderState.fetchStructureState
|
608
|
+
.implementation instanceof QueryBuilderTDSState
|
609
|
+
) ||
|
610
|
+
!resultState.queryBuilderState.isQuerySupported ||
|
611
|
+
!resultState.mousedOverCell
|
612
|
+
}
|
613
|
+
menuProps={{ elevation: 7 }}
|
614
|
+
key={params.value as string}
|
615
|
+
className={clsx('ag-theme-balham-dark query-builder__result__tds-grid')}
|
616
|
+
>
|
617
|
+
<div
|
618
|
+
className={clsx('query-builder__result__values__table__cell', {
|
619
|
+
'query-builder__result__values__table__cell--active':
|
620
|
+
cellInFilteredResults,
|
621
|
+
})}
|
622
|
+
onMouseDown={(event) => mouseDown(event)}
|
623
|
+
onMouseUp={(event) => mouseUp(event)}
|
624
|
+
onMouseOver={(event) => mouseOver(event)}
|
625
|
+
>
|
626
|
+
<span>{cellValue}</span>
|
627
|
+
</div>
|
628
|
+
</ContextMenu>
|
629
|
+
);
|
630
|
+
},
|
631
|
+
);
|
632
|
+
|
352
633
|
const QueryBuilderGridResult = observer(
|
353
634
|
(props: {
|
354
635
|
executionResult: TDSExecutionResult;
|
355
636
|
queryBuilderState: QueryBuilderState;
|
356
637
|
}) => {
|
357
638
|
const { executionResult, queryBuilderState } = props;
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
null,
|
362
|
-
);
|
363
|
-
const columns = executionResult.result.columns;
|
639
|
+
|
640
|
+
const resultState = queryBuilderState.resultState;
|
641
|
+
|
364
642
|
const rowData = executionResult.result.rows.map((_row, rowIdx) => {
|
365
643
|
const row: PlainObject = {};
|
366
644
|
const cols = executionResult.result.columns;
|
@@ -370,57 +648,42 @@ const QueryBuilderGridResult = observer(
|
|
370
648
|
// See https://github.com/finos/legend-studio/issues/1008
|
371
649
|
row[cols[colIdx] as string] = isBoolean(value) ? String(value) : value;
|
372
650
|
});
|
651
|
+
|
373
652
|
row.rowNumber = rowIdx;
|
374
653
|
return row;
|
375
654
|
});
|
376
655
|
|
377
656
|
return (
|
378
|
-
<
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
// options use the data belonging to the row that they are
|
409
|
-
// in. hence why we set the cell every time we mouse over
|
410
|
-
// rather than making user click multiple times.
|
411
|
-
onCellMouseOver={(event): void => {
|
412
|
-
cellDoubleClickedEvent.current = event;
|
413
|
-
}}
|
414
|
-
suppressFieldDotNotation={true}
|
415
|
-
columnDefs={columns.map((colName) => ({
|
416
|
-
minWidth: 50,
|
417
|
-
sortable: true,
|
418
|
-
resizable: true,
|
419
|
-
field: colName,
|
420
|
-
flex: 1,
|
421
|
-
}))}
|
422
|
-
/>
|
423
|
-
</ContextMenu>
|
657
|
+
<div className="query-builder__result__values__table">
|
658
|
+
<div
|
659
|
+
className={clsx(
|
660
|
+
'ag-theme-balham-dark query-builder__result__tds-grid',
|
661
|
+
)}
|
662
|
+
>
|
663
|
+
<DataGrid
|
664
|
+
rowData={rowData}
|
665
|
+
gridOptions={{
|
666
|
+
suppressScrollOnNewData: true,
|
667
|
+
getRowId: function (data) {
|
668
|
+
return data.data.rowNumber as string;
|
669
|
+
},
|
670
|
+
}}
|
671
|
+
suppressFieldDotNotation={true}
|
672
|
+
columnDefs={executionResult.result.columns.map((colName) => ({
|
673
|
+
minWidth: 50,
|
674
|
+
sortable: true,
|
675
|
+
resizable: true,
|
676
|
+
field: colName,
|
677
|
+
flex: 1,
|
678
|
+
cellRenderer: QueryResultCellRenderer,
|
679
|
+
cellRendererParams: {
|
680
|
+
resultState: resultState,
|
681
|
+
tdsExecutionResult: executionResult,
|
682
|
+
},
|
683
|
+
}))}
|
684
|
+
/>
|
685
|
+
</div>
|
686
|
+
</div>
|
424
687
|
);
|
425
688
|
},
|
426
689
|
);
|
@@ -532,6 +795,7 @@ export const QueryBuilderResultPanel = observer(
|
|
532
795
|
!queryBuilderState.isQuerySupported || isSupportedQueryValid;
|
533
796
|
|
534
797
|
const runQuery = (): void => {
|
798
|
+
resultState.setSelectedCells([]);
|
535
799
|
resultState.pressedRunQuery.inProgress();
|
536
800
|
if (queryParametersState.parameterStates.length) {
|
537
801
|
queryParametersState.parameterValuesEditorState.open(
|
@@ -565,6 +829,7 @@ export const QueryBuilderResultPanel = observer(
|
|
565
829
|
val === '' ? 0 : parseInt(val, 10),
|
566
830
|
);
|
567
831
|
};
|
832
|
+
|
568
833
|
const allowSettingPreviewLimit = queryBuilderState.isQuerySupported;
|
569
834
|
|
570
835
|
const copyExpression = (value: string): void => {
|
@@ -773,7 +1038,7 @@ export const QueryBuilderResultPanel = observer(
|
|
773
1038
|
className="query-builder__result__export__dropdown__menu__item"
|
774
1039
|
onClick={(): void => confirmExport(format)}
|
775
1040
|
>
|
776
|
-
{
|
1041
|
+
{format}
|
777
1042
|
</MenuContentItem>
|
778
1043
|
))}
|
779
1044
|
</MenuContent>
|