@finos/legend-query-builder 4.14.70 → 4.14.72

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderConstantExpressionPanel.js +2 -1
  3. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  4. package/lib/components/QueryLoader.d.ts.map +1 -1
  5. package/lib/components/QueryLoader.js +12 -34
  6. package/lib/components/QueryLoader.js.map +1 -1
  7. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  8. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +10 -3
  9. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  11. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +2 -2
  12. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
  13. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +6 -2
  15. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  16. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  17. package/lib/components/filter/QueryBuilderFilterPanel.js +5 -1
  18. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  19. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  20. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +5 -16
  21. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  22. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +3 -1
  23. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
  24. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +88 -31
  25. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
  26. package/lib/index.css +2 -2
  27. package/lib/index.css.map +1 -1
  28. package/lib/package.json +1 -1
  29. package/lib/stores/QueryBuilderConstantsState.d.ts +1 -0
  30. package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
  31. package/lib/stores/QueryBuilderConstantsState.js +6 -1
  32. package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
  33. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts +1 -1
  34. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts.map +1 -1
  35. package/lib/stores/QueryBuilderValueSpecificationHelper.js +1 -0
  36. package/lib/stores/QueryBuilderValueSpecificationHelper.js.map +1 -1
  37. package/lib/stores/QueryLoaderState.d.ts +8 -6
  38. package/lib/stores/QueryLoaderState.d.ts.map +1 -1
  39. package/lib/stores/QueryLoaderState.js +30 -7
  40. package/lib/stores/QueryLoaderState.js.map +1 -1
  41. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts +4 -1
  42. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  43. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +22 -11
  44. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  45. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  46. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  47. package/lib/stores/filter/QueryBuilderFilterState.js +8 -4
  48. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  49. package/package.json +3 -3
  50. package/src/components/QueryBuilderConstantExpressionPanel.tsx +2 -1
  51. package/src/components/QueryLoader.tsx +37 -54
  52. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +24 -2
  53. package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +6 -2
  54. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +10 -2
  55. package/src/components/filter/QueryBuilderFilterPanel.tsx +10 -1
  56. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +8 -16
  57. package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +96 -34
  58. package/src/stores/QueryBuilderConstantsState.ts +16 -1
  59. package/src/stores/QueryBuilderValueSpecificationHelper.ts +2 -1
  60. package/src/stores/QueryLoaderState.ts +43 -17
  61. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +39 -10
  62. package/src/stores/filter/QueryBuilderFilterState.ts +11 -3
@@ -746,7 +746,8 @@ export const QueryResultModifierModal = observer(
746
746
  classes={{
747
747
  root: 'editor-modal__root-container',
748
748
  container: 'editor-modal__container',
749
- paper: 'editor-modal__content',
749
+ paper:
750
+ 'editor-modal__content query-builder__projection__modal__content',
750
751
  }}
751
752
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL}
752
753
  >
@@ -756,7 +757,10 @@ export const QueryResultModifierModal = observer(
756
757
  }
757
758
  className="editor-modal query-builder__projection__modal"
758
759
  >
759
- <ModalHeader title="Query Options" />
760
+ <ModalHeader
761
+ className="query-builder__projection__modal__header"
762
+ title="Query Options"
763
+ />
760
764
  <ModalBody className="query-builder__projection__modal__body">
761
765
  <div className="query-builder__projection__options">
762
766
  {tdsState.queryBuilderState.milestoningState
@@ -214,7 +214,8 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
214
214
  }) => {
215
215
  const { projectionColumnState } = props;
216
216
  const hasParserError = projectionColumnState.tdsState.hasParserError;
217
- const onEditorBlur = (): void => {
217
+
218
+ const onEditorBlur = useCallback((): void => {
218
219
  flowResult(
219
220
  projectionColumnState.fetchDerivationLambdaReturnType({
220
221
  forceConversionStringToLambda: true,
@@ -224,7 +225,8 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
224
225
  projectionColumnState.tdsState.queryBuilderState.applicationStore
225
226
  .alertUnhandledError,
226
227
  );
227
- };
228
+ }, [projectionColumnState]);
229
+
228
230
  const handleDrop = useCallback(
229
231
  (
230
232
  item: QueryBuilderDerivationProjectionColumnDropTarget,
@@ -256,6 +258,7 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
256
258
  },
257
259
  [projectionColumnState],
258
260
  );
261
+
259
262
  const [, dropConnector] =
260
263
  useDrop<QueryBuilderDerivationProjectionColumnDropTarget>(
261
264
  () => ({
@@ -269,6 +272,11 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
269
272
  [handleDrop],
270
273
  );
271
274
 
275
+ // Calculate derivation return type on mount
276
+ useEffect(() => {
277
+ onEditorBlur();
278
+ }, [onEditorBlur]);
279
+
272
280
  return (
273
281
  <div
274
282
  ref={dropConnector}
@@ -1020,13 +1020,22 @@ const QueryBuilderFilterConditionEditor = observer(
1020
1020
  rightConditionValue instanceof FilterValueSpecConditionValueState &&
1021
1021
  rightConditionValue.value
1022
1022
  ) {
1023
+ const isInvalidVariable =
1024
+ rightConditionValue.value instanceof VariableExpression &&
1025
+ node.condition.filterState.isInvalidValueSpecFilterValue(node);
1023
1026
  return (
1024
1027
  <div
1025
1028
  ref={dropConnector}
1026
1029
  data-testid={
1027
1030
  QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_VALUE
1028
1031
  }
1029
- className="query-builder-filter-tree__condition-node__value"
1032
+ className={clsx(
1033
+ 'query-builder-filter-tree__condition-node__value',
1034
+ {
1035
+ 'query-builder-filter-tree__condition-node__value--error':
1036
+ isInvalidVariable,
1037
+ },
1038
+ )}
1030
1039
  >
1031
1040
  <PanelEntryDropZonePlaceholder
1032
1041
  isDragOver={isFilterValueDragOver}
@@ -61,7 +61,10 @@ import {
61
61
  Dialog,
62
62
  CustomSelectorInput,
63
63
  } from '@finos/legend-art';
64
- import { getFloatGridColumnCustomHeader } from './QueryBuilderTDSSimpleGridResult.js';
64
+ import {
65
+ getTDSColumnCustomizations,
66
+ MAXIMUM_FRACTION_DIGITS,
67
+ } from './QueryBuilderTDSSimpleGridResult.js';
65
68
 
66
69
  export const enum QueryBuilderDataGridCustomAggregationFunction {
67
70
  wavg = 'wavg',
@@ -88,20 +91,13 @@ const getAggregationTDSColumnCustomizations = (
88
91
  filter: 'agDateColumnFilter',
89
92
  allowedAggFuncs: ['count'],
90
93
  };
94
+ case PRIMITIVE_TYPE.DECIMAL:
91
95
  case PRIMITIVE_TYPE.NUMBER:
92
96
  case PRIMITIVE_TYPE.INTEGER:
93
- return {
94
- filter: 'agNumberColumnFilter',
95
- allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
96
- };
97
- case PRIMITIVE_TYPE.DECIMAL:
98
97
  case PRIMITIVE_TYPE.FLOAT:
99
98
  return {
100
99
  filter: 'agNumberColumnFilter',
101
100
  allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
102
- headerComponentParams: {
103
- template: getFloatGridColumnCustomHeader(columnName),
104
- },
105
101
  };
106
102
  default:
107
103
  return {
@@ -117,7 +113,7 @@ const QueryResultCellRenderer = observer(
117
113
  const formattedCellValue = (): QueryBuilderTDSResultCellDataType => {
118
114
  if (isNumber(cellValue)) {
119
115
  return Intl.NumberFormat(DEFAULT_LOCALE, {
120
- maximumFractionDigits: 4,
116
+ maximumFractionDigits: MAXIMUM_FRACTION_DIGITS,
121
117
  }).format(Number(cellValue));
122
118
  } else if (isBoolean(cellValue)) {
123
119
  return String(cellValue);
@@ -181,6 +177,7 @@ const getLocalColDefs = (
181
177
  tdsExecutionResult: executionResult,
182
178
  },
183
179
  ...getAggregationTDSColumnCustomizations(executionResult, colName),
180
+ ...getTDSColumnCustomizations(executionResult, colName),
184
181
  } as DataGridColumnDefinition;
185
182
  const persistedColumn = resultState.gridConfig?.columns.find(
186
183
  (c) => c.colId === colName,
@@ -216,15 +213,9 @@ const getFilterTDSColumnCustomizations = (
216
213
  case PRIMITIVE_TYPE.DECIMAL:
217
214
  case PRIMITIVE_TYPE.INTEGER:
218
215
  case PRIMITIVE_TYPE.NUMBER:
219
- return {
220
- filter: 'agNumberColumnFilter',
221
- };
222
216
  case PRIMITIVE_TYPE.FLOAT:
223
217
  return {
224
218
  filter: 'agNumberColumnFilter',
225
- headerComponentParams: {
226
- template: getFloatGridColumnCustomHeader(columnName),
227
- },
228
219
  };
229
220
  default:
230
221
  // we default all other columns to use filter true which defaults to set filters
@@ -255,6 +246,7 @@ const getColDefs = (
255
246
  tdsExecutionResult: executionResult,
256
247
  },
257
248
  ...getFilterTDSColumnCustomizations(executionResult, colName),
249
+ ...getTDSColumnCustomizations(executionResult, colName),
258
250
  }) as DataGridColumnDefinition,
259
251
  );
260
252
 
@@ -48,45 +48,107 @@ import type {
48
48
  } from '../../../stores/QueryBuilderResultState.js';
49
49
  import { QUERY_BUILDER_TEST_ID } from '../../../__lib__/QueryBuilderTesting.js';
50
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>`;
51
+ export const MAXIMUM_FRACTION_DIGITS = 4;
52
+
53
+ export const getFloatGridColumnCustomHeader = (): string =>
54
+ `<div class="ag-cell-label-container" role="presentation">
55
+ <span
56
+ data-ref="eMenu"
57
+ class="ag-header-icon ag-header-cell-menu-button"
58
+ ></span>
59
+ <span
60
+ data-ref="eFilterButton"
61
+ class="ag-header-icon ag-header-cell-filter-button"
62
+ ></span>
63
+ <div data-ref="eLabel" class="ag-header-cell-label" role="presentation">
64
+ <span
65
+ data-ref="eSortOrder"
66
+ class="ag-header-icon ag-sort-order ag-hidden"
67
+ ></span>
68
+ <span
69
+ data-ref="eSortAsc"
70
+ class="ag-header-icon ag-sort-ascending-icon ag-hidden"
71
+ ></span>
72
+ <span
73
+ data-ref="eSortDesc"
74
+ class="ag-header-icon ag-sort-descending-icon ag-hidden"
75
+ ></span>
76
+ <span
77
+ data-ref="eSortMixed"
78
+ class="ag-header-icon ag-sort-mixed-icon ag-hidden"
79
+ ></span>
80
+ <span
81
+ data-ref="eSortNone"
82
+ class="ag-header-icon ag-sort-none-icon ag-hidden"
83
+ ></span>
84
+ <span
85
+ data-ref="eText"
86
+ class="ag-header-cell-text"
87
+ role="columnheader"
88
+ ></span>
89
+ <span data-ref="eFilter" class="ag-header-icon ag-filter-icon"></span>
90
+ </div>
91
+ <div
92
+ data-testid="query__builder__result__grid__custom-header"
93
+ class="query-builder__result__values__table__custom-header"
94
+ >
95
+ <div
96
+ class="query-builder__result__values__table__custom-header__icon"
97
+ title="some values have been rounded using en-us format in this preview grid (defaults to max 4 decimal places)"
98
+ >
99
+ <svg
100
+ stroke="currentColor"
101
+ fill="currentColor"
102
+ stroke-width="0"
103
+ viewBox="0 0 576 512"
104
+ height="1em"
105
+ width="1em"
106
+ xmlns="http://www.w3.org/2000/svg"
107
+ >
108
+ <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>
109
+ </svg>
110
+ </div>
111
+ </div>
112
+ </div>`;
72
113
 
73
- const getTDSColumnCustomizations = (
114
+ export const getTDSColumnCustomizations = (
74
115
  result: TDSExecutionResult,
75
116
  columnName: string,
76
117
  ): object => {
77
- const columnType = result.builder.columns.find(
118
+ const index = result.builder.columns.findIndex(
78
119
  (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 {};
120
+ );
121
+ if (index >= 0) {
122
+ const columnType = result.builder.columns[index]?.type;
123
+ const colValues = result.result.rows.map((r) => r.values[index]);
124
+ const isTruncated = (
125
+ vals: (string | number | boolean | null | undefined)[],
126
+ ): boolean =>
127
+ Boolean(
128
+ vals.some((val) => {
129
+ if (val) {
130
+ const decimalPart = val.toString().split('.')[1];
131
+ return decimalPart && decimalPart.length > MAXIMUM_FRACTION_DIGITS;
132
+ }
133
+ return false;
134
+ }),
135
+ );
136
+ switch (columnType) {
137
+ case PRIMITIVE_TYPE.NUMBER:
138
+ case PRIMITIVE_TYPE.DECIMAL:
139
+ case PRIMITIVE_TYPE.FLOAT:
140
+ return isTruncated(colValues)
141
+ ? {
142
+ headerComponentParams: {
143
+ template: getFloatGridColumnCustomHeader(),
144
+ },
145
+ }
146
+ : {};
147
+ default:
148
+ return {};
149
+ }
89
150
  }
151
+ return {};
90
152
  };
91
153
 
92
154
  const QueryResultCellRenderer = observer(
@@ -104,7 +166,7 @@ const QueryResultCellRenderer = observer(
104
166
  const formattedCellValue = (): QueryBuilderTDSResultCellDataType => {
105
167
  if (isNumber(cellValue)) {
106
168
  return Intl.NumberFormat(DEFAULT_LOCALE, {
107
- maximumFractionDigits: 4,
169
+ maximumFractionDigits: MAXIMUM_FRACTION_DIGITS,
108
170
  }).format(Number(cellValue));
109
171
  } else if (isBoolean(cellValue)) {
110
172
  return String(cellValue);
@@ -288,6 +288,7 @@ export class QueryBuilderCalculatedConstantExpressionState
288
288
  variable: observable,
289
289
  lambdaState: observable,
290
290
  value: observable,
291
+ setLambdaState: action,
291
292
  setValue: action,
292
293
  });
293
294
  this.value = value;
@@ -298,6 +299,10 @@ export class QueryBuilderCalculatedConstantExpressionState
298
299
  );
299
300
  }
300
301
 
302
+ setLambdaState(val: QueryBuilderConstantLambdaEditorState): void {
303
+ this.lambdaState = val;
304
+ }
305
+
301
306
  setValue(val: PlainObject): void {
302
307
  this.value = val;
303
308
  }
@@ -393,8 +398,18 @@ export class QueryBuilderConstantsState implements Hashable {
393
398
  export const cloneQueryBuilderConstantLambdaEditorState = (
394
399
  state: QueryBuilderConstantLambdaEditorState,
395
400
  ): QueryBuilderConstantLambdaEditorState => {
401
+ const clonedCalculatedState =
402
+ new QueryBuilderCalculatedConstantExpressionState(
403
+ state.calculatedState.queryBuilderState,
404
+ new VariableExpression(
405
+ state.calculatedState.variable.name,
406
+ state.calculatedState.variable.multiplicity,
407
+ state.calculatedState.variable.genericType,
408
+ ),
409
+ deepClone(state.calculatedState.value),
410
+ );
396
411
  const clonedState = new QueryBuilderConstantLambdaEditorState(
397
- deepClone(state.calculatedState),
412
+ clonedCalculatedState,
398
413
  );
399
414
  clonedState.lambdaString = state.lambdaString;
400
415
  clonedState.parserError = deepClone(state.parserError);
@@ -213,7 +213,7 @@ export const isPropertyExpressionChainOptional = (
213
213
 
214
214
  export const isTypeCompatibleForAssignment = (
215
215
  type: Type | undefined,
216
- assignmentType: Type,
216
+ assignmentType: Type | undefined,
217
217
  ): boolean => {
218
218
  const NUMERIC_PRIMITIVE_TYPES = [
219
219
  PRIMITIVE_TYPE.NUMBER,
@@ -231,6 +231,7 @@ export const isTypeCompatibleForAssignment = (
231
231
  // When changing the return type for LHS, the RHS value should be adjusted accordingly.
232
232
  return (
233
233
  type !== undefined &&
234
+ assignmentType !== undefined &&
234
235
  // Numeric value is handled loosely because of autoboxing
235
236
  // e.g. LHS (integer) = RHS (float) is acceptable
236
237
  ((NUMERIC_PRIMITIVE_TYPES.includes(type.path) &&
@@ -19,17 +19,18 @@ import {
19
19
  type GenericLegendApplicationStore,
20
20
  } from '@finos/legend-application';
21
21
  import {
22
- QuerySearchSpecification,
23
- GRAPH_MANAGER_EVENT,
24
22
  type QueryInfo,
25
23
  type LightQuery,
26
24
  type BasicGraphManagerState,
27
25
  type Query,
28
26
  type RawLambda,
27
+ QuerySearchSpecification,
28
+ GRAPH_MANAGER_EVENT,
29
+ QuerySearchSortBy,
29
30
  } from '@finos/legend-graph';
30
31
  import {
31
- ActionState,
32
32
  type GeneratorFn,
33
+ ActionState,
33
34
  assertErrorThrown,
34
35
  guaranteeNonNullable,
35
36
  LogEvent,
@@ -51,7 +52,7 @@ export enum SORT_BY_OPTIONS {
51
52
  SORT_BY_UPDATE = 'Last Updated',
52
53
  }
53
54
 
54
- export type SortByOption = { label: string; value: string };
55
+ export type SortByOption = { label: SORT_BY_OPTIONS; value: SORT_BY_OPTIONS };
55
56
 
56
57
  export class QueryLoaderState {
57
58
  readonly applicationStore: GenericLegendApplicationStore;
@@ -92,7 +93,7 @@ export class QueryLoaderState {
92
93
  showingDefaultQueries = true;
93
94
  showPreviewViewer = false;
94
95
  queryPreviewContent?: QueryInfo | { name: string; content: string };
95
- sortBy = '';
96
+ sortBy = SORT_BY_OPTIONS.SORT_BY_VIEW;
96
97
 
97
98
  constructor(
98
99
  applicationStore: GenericLegendApplicationStore,
@@ -158,10 +159,23 @@ export class QueryLoaderState {
158
159
  this.isCuratedTemplateToggled = val;
159
160
  }
160
161
 
161
- setSortBy(val: string): void {
162
+ setSortBy(val: SORT_BY_OPTIONS): void {
162
163
  this.sortBy = val;
163
164
  }
164
165
 
166
+ getQuerySearchSortBy(sortByValue: string): QuerySearchSortBy | undefined {
167
+ switch (sortByValue) {
168
+ case SORT_BY_OPTIONS.SORT_BY_CREATE:
169
+ return QuerySearchSortBy.SORT_BY_CREATE;
170
+ case SORT_BY_OPTIONS.SORT_BY_UPDATE:
171
+ return QuerySearchSortBy.SORT_BY_UPDATE;
172
+ case SORT_BY_OPTIONS.SORT_BY_VIEW:
173
+ return QuerySearchSortBy.SORT_BY_VIEW;
174
+ default:
175
+ return undefined;
176
+ }
177
+ }
178
+
165
179
  setSearchText(val: string): void {
166
180
  this.searchText = val;
167
181
  }
@@ -171,7 +185,16 @@ export class QueryLoaderState {
171
185
  }
172
186
 
173
187
  setQueries(val: LightQuery[]): void {
174
- this.queries = val.sort((a, b) => a.name.localeCompare(b.name));
188
+ this.queries = val;
189
+ }
190
+
191
+ // search query using search specification
192
+ canPerformAdvancedSearch(searchText: string): boolean {
193
+ return !(
194
+ searchText.length < DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH &&
195
+ !this.showCurrentUserQueriesOnly &&
196
+ Array.from(this.extraFilters.values()).every((value) => value === false)
197
+ );
175
198
  }
176
199
 
177
200
  setShowPreviewViewer(val: boolean): void {
@@ -226,11 +249,7 @@ export class QueryLoaderState {
226
249
  }
227
250
 
228
251
  *searchQueries(searchText: string): GeneratorFn<void> {
229
- if (
230
- searchText.length < DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH &&
231
- !this.showCurrentUserQueriesOnly &&
232
- Array.from(this.extraFilters.values()).every((value) => value === false)
233
- ) {
252
+ if (!this.canPerformAdvancedSearch(searchText)) {
234
253
  // if no search text is specified, use fetch the default queries
235
254
  if (!searchText) {
236
255
  this.showingDefaultQueries = true;
@@ -268,6 +287,10 @@ export class QueryLoaderState {
268
287
  searchSpecification.limit = QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT + 1;
269
288
  searchSpecification.showCurrentUserQueriesOnly =
270
289
  this.showCurrentUserQueriesOnly;
290
+ const querySearchSortBy = this.getQuerySearchSortBy(this.sortBy);
291
+ if (querySearchSortBy) {
292
+ searchSpecification.sortByOption = querySearchSortBy;
293
+ }
271
294
  if (this.queryBuilderState) {
272
295
  Array.from(this.extraFilters.entries()).forEach(([key, value]) => {
273
296
  if (value) {
@@ -288,11 +311,14 @@ export class QueryLoaderState {
288
311
  searchSpecification =
289
312
  this.decorateSearchSpecification?.(searchSpecification) ??
290
313
  searchSpecification;
291
- this.queries = (
292
- (yield this.graphManagerState.graphManager.searchQueries(
293
- searchSpecification,
294
- )) as LightQuery[]
295
- ).sort((a, b) => a.name.localeCompare(b.name));
314
+ this.queries = (yield this.graphManagerState.graphManager.searchQueries(
315
+ searchSpecification,
316
+ )) as LightQuery[];
317
+ if (!querySearchSortBy) {
318
+ this.queries = this.queries.sort((a, b) =>
319
+ a.name.localeCompare(b.name),
320
+ );
321
+ }
296
322
  this.searchQueriesState.pass();
297
323
  } catch (error) {
298
324
  assertErrorThrown(error);
@@ -20,12 +20,12 @@ import {
20
20
  type Type,
21
21
  type ValueSpecification,
22
22
  type ExecutionResult,
23
- type VariableExpression,
24
23
  type SimpleFunctionExpression,
25
24
  observe_ValueSpecification,
26
25
  PrimitiveType,
27
26
  CollectionInstanceValue,
28
27
  InstanceValue,
28
+ VariableExpression,
29
29
  } from '@finos/legend-graph';
30
30
  import {
31
31
  type GeneratorFn,
@@ -74,11 +74,13 @@ import type { QueryBuilderTDSColumnState } from '../QueryBuilderTDSColumnState.j
74
74
  import {
75
75
  getCollectionValueSpecificationType,
76
76
  getNonCollectionValueSpecificationType,
77
+ isTypeCompatibleForAssignment,
77
78
  isValidInstanceValue,
78
79
  isValueExpressionReferencedInValue,
79
80
  } from '../../../QueryBuilderValueSpecificationHelper.js';
80
81
  import { buildtdsPropertyExpressionFromColState } from './operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js';
81
82
  import { TDS_COLUMN_GETTER } from '../../../../graph/QueryBuilderMetaModelConst.js';
83
+ import type { QueryBuilderFilterTreeNodeData } from '../../../filter/QueryBuilderFilterState.js';
82
84
 
83
85
  export enum QUERY_BUILDER_POST_FILTER_DND_TYPE {
84
86
  GROUP_CONDITION = 'QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION',
@@ -1011,15 +1013,45 @@ export class QueryBuilderPostFilterState
1011
1013
  );
1012
1014
  }
1013
1015
 
1016
+ isInvalidValueSpecPostFilterValue(
1017
+ node: QueryBuilderPostFilterTreeNodeData,
1018
+ ): boolean {
1019
+ return (
1020
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1021
+ node.condition.rightConditionValue instanceof
1022
+ PostFilterValueSpecConditionValueState &&
1023
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1024
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1025
+ (node.condition.rightConditionValue.value instanceof
1026
+ VariableExpression &&
1027
+ !isTypeCompatibleForAssignment(
1028
+ node.condition.leftConditionValue.getColumnType(),
1029
+ node.condition.rightConditionValue.type,
1030
+ )))
1031
+ );
1032
+ }
1033
+
1034
+ isInvalidTDSColumnPostFilterValue(
1035
+ node: QueryBuilderFilterTreeNodeData,
1036
+ ): boolean {
1037
+ return (
1038
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1039
+ node.condition.rightConditionValue instanceof
1040
+ PostFilterTDSColumnValueConditionValueState &&
1041
+ !isTypeCompatibleForAssignment(
1042
+ node.condition.leftConditionValue.getColumnType(),
1043
+ node.condition.rightConditionValue.type,
1044
+ )
1045
+ );
1046
+ }
1047
+
1014
1048
  get allValidationIssues(): string[] {
1015
1049
  const validationIssues: string[] = [];
1016
1050
  Array.from(this.nodes.values()).forEach((node) => {
1017
1051
  if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
1018
1052
  if (
1019
- node.condition.rightConditionValue instanceof
1020
- PostFilterValueSpecConditionValueState &&
1021
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1022
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1053
+ this.isInvalidValueSpecPostFilterValue(node) ||
1054
+ this.isInvalidTDSColumnPostFilterValue(node)
1023
1055
  ) {
1024
1056
  validationIssues.push(
1025
1057
  `Filter value for ${node.condition.leftConditionValue.columnName} is missing or invalid`,
@@ -1042,11 +1074,8 @@ export class QueryBuilderPostFilterState
1042
1074
  get hasInvalidFilterValues(): boolean {
1043
1075
  return Array.from(this.nodes.values()).some(
1044
1076
  (node) =>
1045
- node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1046
- node.condition.rightConditionValue instanceof
1047
- PostFilterValueSpecConditionValueState &&
1048
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1049
- !isValidInstanceValue(node.condition.rightConditionValue.value),
1077
+ this.isInvalidValueSpecPostFilterValue(node) ||
1078
+ this.isInvalidTDSColumnPostFilterValue(node),
1050
1079
  );
1051
1080
  }
1052
1081
 
@@ -40,12 +40,12 @@ import {
40
40
  type ExecutionResult,
41
41
  AbstractPropertyExpression,
42
42
  type ValueSpecification,
43
- type VariableExpression,
44
43
  type Type,
45
44
  observe_ValueSpecification,
46
45
  CollectionInstanceValue,
47
46
  InstanceValue,
48
47
  SimpleFunctionExpression,
48
+ VariableExpression,
49
49
  matchFunctionName,
50
50
  } from '@finos/legend-graph';
51
51
  import { DEFAULT_LAMBDA_VARIABLE_NAME } from '../QueryBuilderConfig.js';
@@ -61,6 +61,7 @@ import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../QueryBuilderStateHashUtil
61
61
  import {
62
62
  getCollectionValueSpecificationType,
63
63
  getNonCollectionValueSpecificationType,
64
+ isTypeCompatibleForAssignment,
64
65
  isValidInstanceValue,
65
66
  isValueExpressionReferencedInValue,
66
67
  } from '../QueryBuilderValueSpecificationHelper.js';
@@ -1185,8 +1186,15 @@ export class QueryBuilderFilterState
1185
1186
  node instanceof QueryBuilderFilterTreeConditionNodeData &&
1186
1187
  node.condition.rightConditionValue instanceof
1187
1188
  FilterValueSpecConditionValueState &&
1188
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1189
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1189
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1190
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1191
+ (node.condition.rightConditionValue.value instanceof
1192
+ VariableExpression &&
1193
+ !isTypeCompatibleForAssignment(
1194
+ node.condition.propertyExpressionState.propertyExpression.func.value
1195
+ .genericType.value.rawType,
1196
+ node.condition.rightConditionValue.value.genericType?.value.rawType,
1197
+ )))
1190
1198
  );
1191
1199
  }
1192
1200