@finos/legend-query-builder 4.14.44 → 4.14.46
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts +3 -3
- package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts.map +1 -1
- 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/QueryBuilder.d.ts.map +1 -1
- package/lib/components/QueryBuilder.js +5 -2
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +93 -2
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
- package/lib/graph/QueryBuilderMetaModelConst.d.ts +1 -0
- package/lib/graph/QueryBuilderMetaModelConst.d.ts.map +1 -1
- package/lib/graph/QueryBuilderMetaModelConst.js +1 -0
- package/lib/graph/QueryBuilderMetaModelConst.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/package.json +5 -4
- package/lib/stores/QueryBuilderState.d.ts +5 -5
- package/lib/stores/QueryBuilderState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderState.js.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.d.ts +1 -0
- package/lib/stores/QueryBuilderStateHashUtils.d.ts.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.js +1 -0
- package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +2 -0
- package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperator.d.ts +2 -0
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperator.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperator.js +8 -0
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperator.js.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperatorLoader.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperatorLoader.js +2 -0
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperatorLoader.js.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.d.ts +1 -0
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js +7 -3
- package/lib/stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperatorValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.d.ts +37 -0
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.d.ts.map +1 -0
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.js +123 -0
- package/lib/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.js.map +1 -0
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +3 -7
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
- package/package.json +13 -12
- package/src/__lib__/QueryBuilderTelemetryHelper.ts +3 -3
- package/src/__lib__/QueryBuilderTesting.ts +1 -0
- package/src/components/QueryBuilder.tsx +5 -2
- package/src/components/fetch-structure/QueryBuilderFetchStructurePanel.tsx +0 -1
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +208 -4
- package/src/graph/QueryBuilderMetaModelConst.ts +1 -0
- package/src/index.ts +1 -1
- package/src/stores/QueryBuilderState.ts +5 -5
- package/src/stores/QueryBuilderStateHashUtils.ts +1 -0
- package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +5 -0
- package/src/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperator.ts +10 -0
- package/src/stores/fetch-structure/tds/aggregation/QueryBuilderAggregateOperatorLoader.ts +2 -0
- package/src/stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.ts +9 -3
- package/src/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperatorValueSpecificationBuilder.ts +0 -1
- package/src/stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.ts +241 -0
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +3 -7
- package/tsconfig.json +1 -0
@@ -41,6 +41,8 @@ import {
|
|
41
41
|
FunctionIcon,
|
42
42
|
CogIcon,
|
43
43
|
InfoCircleIcon,
|
44
|
+
BasePopover,
|
45
|
+
InputWithInlineValidation,
|
44
46
|
} from '@finos/legend-art';
|
45
47
|
import {
|
46
48
|
type QueryBuilderExplorerTreeDragSource,
|
@@ -116,6 +118,7 @@ import {
|
|
116
118
|
QueryBuilderPropertyInfoTooltip,
|
117
119
|
} from '../shared/QueryBuilderPropertyInfoTooltip.js';
|
118
120
|
import { getNameOfValueSpecification } from '../shared/QueryBuilderVariableSelector.js';
|
121
|
+
import { QueryBuilderAggregateOperator_Percentile } from '../../stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.js';
|
119
122
|
|
120
123
|
const QueryBuilderProjectionColumnContextMenu = observer(
|
121
124
|
forwardRef<
|
@@ -689,6 +692,52 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
689
692
|
}),
|
690
693
|
[handleDrop],
|
691
694
|
);
|
695
|
+
const percentileButtonRef = useRef<HTMLButtonElement>(null);
|
696
|
+
const percentileInputRef = useRef<HTMLInputElement>(null);
|
697
|
+
const [isPercentileOpen, setIsPercentileOpen] = useState(false);
|
698
|
+
const [percentileValue, setPercentileValue] = useState(
|
699
|
+
aggregateColumnState &&
|
700
|
+
aggregateColumnState.operator instanceof
|
701
|
+
QueryBuilderAggregateOperator_Percentile &&
|
702
|
+
aggregateColumnState.operator.percentile !== undefined
|
703
|
+
? (aggregateColumnState.operator.percentile * 100).toString()
|
704
|
+
: '',
|
705
|
+
);
|
706
|
+
const [acending, setAcending] = useState(
|
707
|
+
aggregateColumnState &&
|
708
|
+
aggregateColumnState.operator instanceof
|
709
|
+
QueryBuilderAggregateOperator_Percentile
|
710
|
+
? aggregateColumnState.operator.acending
|
711
|
+
: undefined,
|
712
|
+
);
|
713
|
+
const [continuous, setContinuous] = useState(
|
714
|
+
aggregateColumnState &&
|
715
|
+
aggregateColumnState.operator instanceof
|
716
|
+
QueryBuilderAggregateOperator_Percentile
|
717
|
+
? aggregateColumnState.operator.continuous
|
718
|
+
: undefined,
|
719
|
+
);
|
720
|
+
const percentileOptions = ['true', 'false'].map((op) => ({
|
721
|
+
label: op,
|
722
|
+
value: op,
|
723
|
+
}));
|
724
|
+
const getPercentileDisplayValue = (): string => {
|
725
|
+
if (percentileValue === '') {
|
726
|
+
return '...';
|
727
|
+
}
|
728
|
+
if (acending === undefined || continuous === undefined) {
|
729
|
+
return `${Number(percentileValue)}`;
|
730
|
+
}
|
731
|
+
return `${Number(percentileValue)}, ${acending}, ${continuous}`;
|
732
|
+
};
|
733
|
+
const setPercentileArguments = (): void => {
|
734
|
+
setIsPercentileOpen(!isPercentileOpen);
|
735
|
+
};
|
736
|
+
const onPercentileValueChange: React.ChangeEventHandler<
|
737
|
+
HTMLInputElement
|
738
|
+
> = (event) => {
|
739
|
+
setPercentileValue(event.target.value);
|
740
|
+
};
|
692
741
|
|
693
742
|
return (
|
694
743
|
<PanelDnDEntry
|
@@ -817,12 +866,167 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
817
866
|
<div className="query-builder__projection__column__aggregate">
|
818
867
|
<div className="query-builder__projection__column__aggregate__operator">
|
819
868
|
{aggregateColumnState && (
|
820
|
-
<div className="query-
|
821
|
-
|
822
|
-
|
823
|
-
|
869
|
+
<div className="query-builder__projection__column__aggregate__operator">
|
870
|
+
<div className="query-builder__projection__column__aggregate__operator__label">
|
871
|
+
{aggregateColumnState.operator.getLabel(
|
872
|
+
projectionColumnState,
|
873
|
+
)}
|
874
|
+
{aggregateColumnState.operator instanceof
|
875
|
+
QueryBuilderAggregateOperator_Percentile && (
|
876
|
+
<button
|
877
|
+
className="query-builder__projection__column__aggregate__operator__percentile__badge"
|
878
|
+
ref={percentileButtonRef}
|
879
|
+
onClick={setPercentileArguments}
|
880
|
+
title="Set Percentile Argument(s)..."
|
881
|
+
>
|
882
|
+
{getPercentileDisplayValue()}
|
883
|
+
</button>
|
884
|
+
)}
|
885
|
+
</div>
|
824
886
|
</div>
|
825
887
|
)}
|
888
|
+
{aggregateColumnState && isPercentileOpen && (
|
889
|
+
<BasePopover
|
890
|
+
open={isPercentileOpen}
|
891
|
+
PaperProps={{
|
892
|
+
classes: {
|
893
|
+
root: 'query-builder__projection__column__aggregate__operator__percentile__container__root',
|
894
|
+
},
|
895
|
+
}}
|
896
|
+
className={clsx(
|
897
|
+
'query-builder__projection__column__aggregate__operator__percentile__container',
|
898
|
+
)}
|
899
|
+
anchorEl={percentileButtonRef.current}
|
900
|
+
onClose={() => {
|
901
|
+
const percentileOperator =
|
902
|
+
aggregateColumnState.operator as QueryBuilderAggregateOperator_Percentile;
|
903
|
+
if (percentileValue === '') {
|
904
|
+
percentileOperator.setPercentile(undefined);
|
905
|
+
} else {
|
906
|
+
percentileOperator.setPercentile(
|
907
|
+
Number(percentileValue) / 100,
|
908
|
+
);
|
909
|
+
}
|
910
|
+
if (acending !== undefined && continuous !== undefined) {
|
911
|
+
percentileOperator.setAcending(acending);
|
912
|
+
percentileOperator.setContinuous(continuous);
|
913
|
+
}
|
914
|
+
setIsPercentileOpen(false);
|
915
|
+
}}
|
916
|
+
anchorOrigin={{
|
917
|
+
vertical: 'bottom',
|
918
|
+
horizontal: 'left',
|
919
|
+
}}
|
920
|
+
transformOrigin={{
|
921
|
+
vertical: 'top',
|
922
|
+
horizontal: 'center',
|
923
|
+
}}
|
924
|
+
>
|
925
|
+
<div
|
926
|
+
data-testid={
|
927
|
+
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_PERCENTILE_PANEL
|
928
|
+
}
|
929
|
+
className=""
|
930
|
+
>
|
931
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo">
|
932
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo__label">
|
933
|
+
Percentile
|
934
|
+
<br />
|
935
|
+
(0-100)
|
936
|
+
</div>
|
937
|
+
<div
|
938
|
+
className={clsx(
|
939
|
+
'query-builder__projection__column__aggregate__operator__percentile__argument-combo__value',
|
940
|
+
)}
|
941
|
+
>
|
942
|
+
<InputWithInlineValidation
|
943
|
+
ref={percentileInputRef}
|
944
|
+
className={clsx(
|
945
|
+
'query-builder__projection__column__aggregate__operator__percentile__input input--dark',
|
946
|
+
)}
|
947
|
+
type="text"
|
948
|
+
inputMode="numeric"
|
949
|
+
onChange={onPercentileValueChange}
|
950
|
+
value={percentileValue}
|
951
|
+
error={
|
952
|
+
percentileValue && Number(percentileValue) > 100
|
953
|
+
? `Invalid aggregation agruement for ${aggregateColumnState.columnName}`
|
954
|
+
: undefined
|
955
|
+
}
|
956
|
+
/>
|
957
|
+
</div>
|
958
|
+
</div>
|
959
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo">
|
960
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo__label">
|
961
|
+
Acending
|
962
|
+
</div>
|
963
|
+
<CustomSelectorInput
|
964
|
+
className="query-loader__results__sort-by__selector query-builder__projection__column__aggregate__operator__percentile__argument-combo__value"
|
965
|
+
options={percentileOptions}
|
966
|
+
onChange={(option: {
|
967
|
+
label: string;
|
968
|
+
value: string;
|
969
|
+
}) => {
|
970
|
+
setAcending(option.value === 'true' ? true : false);
|
971
|
+
}}
|
972
|
+
value={{
|
973
|
+
label:
|
974
|
+
acending === undefined
|
975
|
+
? ''
|
976
|
+
: acending
|
977
|
+
? 'true'
|
978
|
+
: 'false',
|
979
|
+
value:
|
980
|
+
acending === undefined
|
981
|
+
? ''
|
982
|
+
: acending
|
983
|
+
? 'true'
|
984
|
+
: 'false',
|
985
|
+
}}
|
986
|
+
darkMode={
|
987
|
+
!applicationStore.layoutService
|
988
|
+
.TEMPORARY__isLightColorThemeEnabled
|
989
|
+
}
|
990
|
+
/>
|
991
|
+
</div>
|
992
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo">
|
993
|
+
<div className="query-builder__projection__column__aggregate__operator__percentile__argument-combo__label">
|
994
|
+
Continous
|
995
|
+
</div>
|
996
|
+
<CustomSelectorInput
|
997
|
+
className="query-loader__results__sort-by__selector query-builder__projection__column__aggregate__operator__percentile__argument-combo__value"
|
998
|
+
options={percentileOptions}
|
999
|
+
onChange={(option: {
|
1000
|
+
label: string;
|
1001
|
+
value: string;
|
1002
|
+
}) =>
|
1003
|
+
setContinuous(
|
1004
|
+
option.value === 'true' ? true : false,
|
1005
|
+
)
|
1006
|
+
}
|
1007
|
+
value={{
|
1008
|
+
label:
|
1009
|
+
continuous === undefined
|
1010
|
+
? ''
|
1011
|
+
: continuous
|
1012
|
+
? 'true'
|
1013
|
+
: 'false',
|
1014
|
+
value:
|
1015
|
+
continuous === undefined
|
1016
|
+
? ''
|
1017
|
+
: continuous
|
1018
|
+
? 'true'
|
1019
|
+
: 'false',
|
1020
|
+
}}
|
1021
|
+
darkMode={
|
1022
|
+
!applicationStore.layoutService
|
1023
|
+
.TEMPORARY__isLightColorThemeEnabled
|
1024
|
+
}
|
1025
|
+
/>
|
1026
|
+
</div>
|
1027
|
+
</div>
|
1028
|
+
</BasePopover>
|
1029
|
+
)}
|
826
1030
|
{isCalendarEnabled &&
|
827
1031
|
aggregateColumnState &&
|
828
1032
|
aggregateCalendarFunctions.length > 0 && (
|
@@ -163,6 +163,7 @@ export enum QUERY_BUILDER_SUPPORTED_FUNCTIONS {
|
|
163
163
|
FROM = 'meta::pure::mapping::from',
|
164
164
|
CHECKED = 'meta::pure::dataQuality::checked',
|
165
165
|
MERGERUNTIMES = 'meta::pure::runtime::mergeRuntimes',
|
166
|
+
PERCENTILE = 'meta::pure::functions::math::percentile',
|
166
167
|
|
167
168
|
// TOTDS
|
168
169
|
TABLE_TO_TDS = 'meta::pure::tds::tableToTDS',
|
package/src/index.ts
CHANGED
@@ -30,7 +30,7 @@ export { QueryBuilderNavigationBlocker } from './components/QueryBuilderNavigati
|
|
30
30
|
export { QueryBuilder } from './components/QueryBuilder.js';
|
31
31
|
export { QUERY_BUILDER_COMPONENT_ELEMENT_ID } from './components/QueryBuilderComponentElement.js';
|
32
32
|
export {
|
33
|
-
type QuerySDLC,
|
33
|
+
type QueryableSourceInfo as QuerySDLC,
|
34
34
|
QueryBuilderState,
|
35
35
|
} from './stores/QueryBuilderState.js';
|
36
36
|
export {
|
@@ -111,9 +111,9 @@ import { QUERY_BUILDER_EVENT } from '../__lib__/QueryBuilderEvent.js';
|
|
111
111
|
import { QueryBuilderChangeHistoryState } from './QueryBuilderChangeHistoryState.js';
|
112
112
|
import { type QueryBuilderWorkflowState } from './query-workflow/QueryBuilderWorkFlowState.js';
|
113
113
|
|
114
|
-
export interface
|
114
|
+
export interface QueryableSourceInfo {}
|
115
115
|
|
116
|
-
export type
|
116
|
+
export type QueryableClassMappingRuntimeInfo = QueryableSourceInfo & {
|
117
117
|
class: string;
|
118
118
|
mapping: string;
|
119
119
|
runtime: string;
|
@@ -169,7 +169,7 @@ export abstract class QueryBuilderState implements CommandRegistrar {
|
|
169
169
|
// NOTE: This property contains information about workflow used
|
170
170
|
// to create this state. This should only be used to add additional
|
171
171
|
// information to query builder analytics.
|
172
|
-
sourceInfo?:
|
172
|
+
sourceInfo?: QueryableSourceInfo | undefined;
|
173
173
|
|
174
174
|
// NOTE: this makes it so that we need to import components in stores code,
|
175
175
|
// we probably want to refactor to an extension mechanism
|
@@ -180,7 +180,7 @@ export abstract class QueryBuilderState implements CommandRegistrar {
|
|
180
180
|
graphManagerState: GraphManagerState,
|
181
181
|
workflowState: QueryBuilderWorkflowState,
|
182
182
|
config: QueryBuilderConfig | undefined,
|
183
|
-
sourceInfo?:
|
183
|
+
sourceInfo?: QueryableSourceInfo | undefined,
|
184
184
|
) {
|
185
185
|
makeObservable(this, {
|
186
186
|
explorerState: observable,
|
@@ -341,7 +341,7 @@ export abstract class QueryBuilderState implements CommandRegistrar {
|
|
341
341
|
* Gets information about the current queryBuilderState.
|
342
342
|
* This information can be used as a part of analytics
|
343
343
|
*/
|
344
|
-
getStateInfo():
|
344
|
+
getStateInfo(): QueryableClassMappingRuntimeInfo | undefined {
|
345
345
|
if (this.sourceInfo) {
|
346
346
|
const classPath = this.class?.path;
|
347
347
|
const mappingPath = this.executionContextState.mapping?.path;
|
@@ -32,6 +32,7 @@ export enum QUERY_BUILDER_STATE_HASH_STRUCTURE {
|
|
32
32
|
AGGREGATE_OPERATOR_STD_DEV_SAMPLE = 'AGGREGATE_OPERATOR_STD_DEV_SAMPLE',
|
33
33
|
AGGREGATE_OPERATOR_SUM = 'AGGREGATE_OPERATOR_SUM',
|
34
34
|
AGGREGATE_COLUMN_STATE = 'AGGREGATE_COLUMN_STATE',
|
35
|
+
AGGREGATE_OPERATOR_PERCENTILE = 'AGGREGATE_OPERATOR_PERCENTILE',
|
35
36
|
AGGREGATION_STATE = 'AGGREGATION_STATE',
|
36
37
|
SIMPLE_PROJECTION_COLUMN_STATE = 'SIMPLE_PROJECTION_COLUMN_STATE',
|
37
38
|
PROPERTY_EXPRESSION_STATE = 'PROPERTY_EXPRESSION_STATE',
|
@@ -139,6 +139,7 @@ export class QueryBuilderTDSState
|
|
139
139
|
super(queryBuilderState, fetchStructureState);
|
140
140
|
|
141
141
|
makeObservable(this, {
|
142
|
+
aggregationState: observable,
|
142
143
|
projectionColumns: observable,
|
143
144
|
isConvertDerivationProjectionObjects: observable,
|
144
145
|
showPostFilterPanel: observable,
|
@@ -343,6 +344,10 @@ export class QueryBuilderTDSState
|
|
343
344
|
}
|
344
345
|
});
|
345
346
|
|
347
|
+
this.aggregationState.allValidationIssues.forEach((issue) =>
|
348
|
+
validationIssues.push(issue),
|
349
|
+
);
|
350
|
+
|
346
351
|
return validationIssues;
|
347
352
|
}
|
348
353
|
|
@@ -35,6 +35,8 @@ export abstract class QueryBuilderAggregateOperator implements Hashable {
|
|
35
35
|
|
36
36
|
constructor() {
|
37
37
|
makeObservable(this, {
|
38
|
+
getOperator: computed,
|
39
|
+
allValidationIssues: computed,
|
38
40
|
hashCode: computed,
|
39
41
|
});
|
40
42
|
}
|
@@ -84,5 +86,13 @@ export abstract class QueryBuilderAggregateOperator implements Hashable {
|
|
84
86
|
return aggregateColumnState.projectionColumnState.getColumnType();
|
85
87
|
}
|
86
88
|
|
89
|
+
get getOperator(): QueryBuilderAggregateOperator {
|
90
|
+
return this;
|
91
|
+
}
|
92
|
+
|
93
|
+
get allValidationIssues(): string[] {
|
94
|
+
return [];
|
95
|
+
}
|
96
|
+
|
87
97
|
abstract get hashCode(): string;
|
88
98
|
}
|
@@ -25,6 +25,7 @@ import { QueryBuilderAggregateOperator_Min } from './operators/QueryBuilderAggre
|
|
25
25
|
import { QueryBuilderAggregateOperator_Max } from './operators/QueryBuilderAggregateOperator_Max.js';
|
26
26
|
import { QueryBuilderAggregateOperator_JoinString } from './operators/QueryBuilderAggregateOperator_JoinString.js';
|
27
27
|
import type { QueryBuilderAggregateOperator } from './QueryBuilderAggregateOperator.js';
|
28
|
+
import { QueryBuilderAggregateOperator_Percentile } from './operators/QueryBuilderAggregateOperator_Percentile.js';
|
28
29
|
|
29
30
|
export const getQueryBuilderCoreAggregrationOperators =
|
30
31
|
(): QueryBuilderAggregateOperator[] => [
|
@@ -35,6 +36,7 @@ export const getQueryBuilderCoreAggregrationOperators =
|
|
35
36
|
new QueryBuilderAggregateOperator_Average(),
|
36
37
|
new QueryBuilderAggregateOperator_Min(),
|
37
38
|
new QueryBuilderAggregateOperator_Max(),
|
39
|
+
new QueryBuilderAggregateOperator_Percentile(),
|
38
40
|
new QueryBuilderAggregateOperator_StdDev_Population(),
|
39
41
|
new QueryBuilderAggregateOperator_StdDev_Sample(),
|
40
42
|
new QueryBuilderAggregateOperator_JoinString(),
|
@@ -136,6 +136,8 @@ export class QueryBuilderAggregationState implements Hashable {
|
|
136
136
|
addColumn: action,
|
137
137
|
changeColumnAggregateOperator: action,
|
138
138
|
disableCalendar: action,
|
139
|
+
|
140
|
+
allValidationIssues: computed,
|
139
141
|
hashCode: computed,
|
140
142
|
});
|
141
143
|
|
@@ -179,7 +181,7 @@ export class QueryBuilderAggregationState implements Hashable {
|
|
179
181
|
`${colName} (${val.getLabel(projectionColumnState)})`,
|
180
182
|
);
|
181
183
|
}
|
182
|
-
aggregateColumnState.setOperator(val);
|
184
|
+
aggregateColumnState.setOperator(val.getOperator);
|
183
185
|
} else {
|
184
186
|
if (!hideOperatorInColumnName) {
|
185
187
|
projectionColumnState.setColumnName(
|
@@ -189,9 +191,9 @@ export class QueryBuilderAggregationState implements Hashable {
|
|
189
191
|
const newAggregateColumnState = new QueryBuilderAggregateColumnState(
|
190
192
|
this,
|
191
193
|
projectionColumnState,
|
192
|
-
val,
|
194
|
+
val.getOperator,
|
193
195
|
);
|
194
|
-
newAggregateColumnState.setOperator(val);
|
196
|
+
newAggregateColumnState.setOperator(val.getOperator);
|
195
197
|
this.addColumn(newAggregateColumnState);
|
196
198
|
|
197
199
|
// automatically move the column to the end
|
@@ -233,6 +235,10 @@ export class QueryBuilderAggregationState implements Hashable {
|
|
233
235
|
});
|
234
236
|
}
|
235
237
|
|
238
|
+
get allValidationIssues(): string[] {
|
239
|
+
return this.columns.map((col) => col.operator.allValidationIssues).flat();
|
240
|
+
}
|
241
|
+
|
236
242
|
get hashCode(): string {
|
237
243
|
return hashArray([
|
238
244
|
QUERY_BUILDER_STATE_HASH_STRUCTURE.AGGREGATION_STATE,
|
@@ -0,0 +1,241 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2020-present, Goldman Sachs
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
import {
|
18
|
+
matchFunctionName,
|
19
|
+
PRIMITIVE_TYPE,
|
20
|
+
type ValueSpecification,
|
21
|
+
SimpleFunctionExpression,
|
22
|
+
VariableExpression,
|
23
|
+
type PureModel,
|
24
|
+
type AbstractPropertyExpression,
|
25
|
+
GenericType,
|
26
|
+
GenericTypeExplicitReference,
|
27
|
+
Multiplicity,
|
28
|
+
PrimitiveInstanceValue,
|
29
|
+
PrimitiveType,
|
30
|
+
extractElementNameFromPath,
|
31
|
+
} from '@finos/legend-graph';
|
32
|
+
import { QueryBuilderAggregateColumnState } from '../QueryBuilderAggregationState.js';
|
33
|
+
import { QueryBuilderAggregateOperator } from '../QueryBuilderAggregateOperator.js';
|
34
|
+
import {
|
35
|
+
type QueryBuilderProjectionColumnState,
|
36
|
+
QueryBuilderSimpleProjectionColumnState,
|
37
|
+
} from '../../projection/QueryBuilderProjectionColumnState.js';
|
38
|
+
import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '../../../../../graph/QueryBuilderMetaModelConst.js';
|
39
|
+
import {
|
40
|
+
type Hashable,
|
41
|
+
hashArray,
|
42
|
+
assertTrue,
|
43
|
+
guaranteeType,
|
44
|
+
} from '@finos/legend-shared';
|
45
|
+
import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../../../../QueryBuilderStateHashUtils.js';
|
46
|
+
import { action, makeObservable, observable } from 'mobx';
|
47
|
+
|
48
|
+
export class QueryBuilderAggregateOperator_Percentile
|
49
|
+
extends QueryBuilderAggregateOperator
|
50
|
+
implements Hashable
|
51
|
+
{
|
52
|
+
percentile: number | undefined;
|
53
|
+
acending: boolean | undefined;
|
54
|
+
continuous: boolean | undefined;
|
55
|
+
|
56
|
+
constructor() {
|
57
|
+
super();
|
58
|
+
makeObservable(this, {
|
59
|
+
percentile: observable,
|
60
|
+
acending: observable,
|
61
|
+
continuous: observable,
|
62
|
+
setPercentile: action,
|
63
|
+
setAcending: action,
|
64
|
+
setContinuous: action,
|
65
|
+
});
|
66
|
+
}
|
67
|
+
|
68
|
+
setPercentile(val: number | undefined) {
|
69
|
+
this.percentile = val;
|
70
|
+
}
|
71
|
+
|
72
|
+
setAcending(val: boolean | undefined) {
|
73
|
+
this.acending = val;
|
74
|
+
}
|
75
|
+
|
76
|
+
setContinuous(val: boolean | undefined) {
|
77
|
+
this.continuous = val;
|
78
|
+
}
|
79
|
+
|
80
|
+
getLabel(projectionColumnState: QueryBuilderProjectionColumnState): string {
|
81
|
+
return 'percentile';
|
82
|
+
}
|
83
|
+
|
84
|
+
isCompatibleWithColumn(
|
85
|
+
projectionColumnState: QueryBuilderProjectionColumnState,
|
86
|
+
): boolean {
|
87
|
+
if (
|
88
|
+
projectionColumnState instanceof QueryBuilderSimpleProjectionColumnState
|
89
|
+
) {
|
90
|
+
const propertyType =
|
91
|
+
projectionColumnState.propertyExpressionState.propertyExpression.func
|
92
|
+
.value.genericType.value.rawType;
|
93
|
+
return (
|
94
|
+
[
|
95
|
+
PRIMITIVE_TYPE.NUMBER,
|
96
|
+
PRIMITIVE_TYPE.INTEGER,
|
97
|
+
PRIMITIVE_TYPE.DECIMAL,
|
98
|
+
PRIMITIVE_TYPE.FLOAT,
|
99
|
+
] as string[]
|
100
|
+
).includes(propertyType.path);
|
101
|
+
}
|
102
|
+
return true;
|
103
|
+
}
|
104
|
+
|
105
|
+
buildAggregateExpression(
|
106
|
+
propertyExpression: AbstractPropertyExpression | undefined,
|
107
|
+
variableName: string,
|
108
|
+
graph: PureModel,
|
109
|
+
): ValueSpecification {
|
110
|
+
const percentileValue = this.percentile ?? 0;
|
111
|
+
const expression = new SimpleFunctionExpression(
|
112
|
+
extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.PERCENTILE),
|
113
|
+
);
|
114
|
+
const percentile = new PrimitiveInstanceValue(
|
115
|
+
GenericTypeExplicitReference.create(
|
116
|
+
new GenericType(PrimitiveType.NUMBER),
|
117
|
+
),
|
118
|
+
);
|
119
|
+
percentile.values = [percentileValue];
|
120
|
+
if (
|
121
|
+
this.acending === undefined ||
|
122
|
+
this.continuous === undefined ||
|
123
|
+
(this.acending && this.continuous)
|
124
|
+
) {
|
125
|
+
expression.parametersValues.push(
|
126
|
+
new VariableExpression(variableName, Multiplicity.ONE),
|
127
|
+
percentile,
|
128
|
+
);
|
129
|
+
} else {
|
130
|
+
const acending = new PrimitiveInstanceValue(
|
131
|
+
GenericTypeExplicitReference.create(
|
132
|
+
new GenericType(PrimitiveType.BOOLEAN),
|
133
|
+
),
|
134
|
+
);
|
135
|
+
acending.values = [this.acending];
|
136
|
+
const continuous = new PrimitiveInstanceValue(
|
137
|
+
GenericTypeExplicitReference.create(
|
138
|
+
new GenericType(PrimitiveType.BOOLEAN),
|
139
|
+
),
|
140
|
+
);
|
141
|
+
continuous.values = [this.continuous];
|
142
|
+
expression.parametersValues.push(
|
143
|
+
new VariableExpression(variableName, Multiplicity.ONE),
|
144
|
+
percentile,
|
145
|
+
acending,
|
146
|
+
continuous,
|
147
|
+
);
|
148
|
+
}
|
149
|
+
return expression;
|
150
|
+
}
|
151
|
+
|
152
|
+
buildAggregateColumnState(
|
153
|
+
expression: SimpleFunctionExpression,
|
154
|
+
lambdaParam: VariableExpression,
|
155
|
+
projectionColumnState: QueryBuilderProjectionColumnState,
|
156
|
+
): QueryBuilderAggregateColumnState | undefined {
|
157
|
+
if (
|
158
|
+
matchFunctionName(
|
159
|
+
expression.functionName,
|
160
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.PERCENTILE,
|
161
|
+
)
|
162
|
+
) {
|
163
|
+
const aggregateColumnState = new QueryBuilderAggregateColumnState(
|
164
|
+
projectionColumnState.tdsState.aggregationState,
|
165
|
+
projectionColumnState,
|
166
|
+
new QueryBuilderAggregateOperator_Percentile(),
|
167
|
+
);
|
168
|
+
|
169
|
+
const currentOperator = guaranteeType(
|
170
|
+
aggregateColumnState.operator,
|
171
|
+
QueryBuilderAggregateOperator_Percentile,
|
172
|
+
);
|
173
|
+
|
174
|
+
aggregateColumnState.setLambdaParameterName(lambdaParam.name);
|
175
|
+
|
176
|
+
assertTrue(
|
177
|
+
[2, 4].includes(expression.parametersValues.length),
|
178
|
+
`Can't process percentile() expression: percentile() expects 2 or 4 argument`,
|
179
|
+
);
|
180
|
+
|
181
|
+
// variable
|
182
|
+
const variableExpression = guaranteeType(
|
183
|
+
expression.parametersValues[0],
|
184
|
+
VariableExpression,
|
185
|
+
`Can't process percentile() expression: only support percentile() immediately following a variable expression`,
|
186
|
+
);
|
187
|
+
assertTrue(
|
188
|
+
aggregateColumnState.lambdaParameterName === variableExpression.name,
|
189
|
+
`Can't process percentile() expression: expects variable used in lambda body '${variableExpression.name}' to match lambda parameter '${aggregateColumnState.lambdaParameterName}'`,
|
190
|
+
);
|
191
|
+
const percentile = guaranteeType(
|
192
|
+
expression.parametersValues[1],
|
193
|
+
PrimitiveInstanceValue,
|
194
|
+
`Can't process percentile() expression: percentile() expects arugment #2 to be a primitive instance value`,
|
195
|
+
);
|
196
|
+
currentOperator.percentile = percentile.values[0] as number;
|
197
|
+
|
198
|
+
if (expression.parametersValues.length === 4) {
|
199
|
+
const acending = guaranteeType(
|
200
|
+
expression.parametersValues[2],
|
201
|
+
PrimitiveInstanceValue,
|
202
|
+
`Can't process percentile() expression: percentile() expects arugment #3 to be a primitive instance value`,
|
203
|
+
);
|
204
|
+
currentOperator.acending = acending.values[0] as boolean;
|
205
|
+
const continuous = guaranteeType(
|
206
|
+
expression.parametersValues[3],
|
207
|
+
PrimitiveInstanceValue,
|
208
|
+
`Can't process percentile() expression: percentile() expects arugment #4 to be a primitive instance value`,
|
209
|
+
);
|
210
|
+
currentOperator.continuous = continuous.values[0] as boolean;
|
211
|
+
}
|
212
|
+
// operator
|
213
|
+
assertTrue(
|
214
|
+
this.isCompatibleWithColumn(aggregateColumnState.projectionColumnState),
|
215
|
+
`Can't process percentile() expression: property is not compatible with operator`,
|
216
|
+
);
|
217
|
+
aggregateColumnState.setOperator(currentOperator);
|
218
|
+
return aggregateColumnState;
|
219
|
+
}
|
220
|
+
|
221
|
+
return undefined;
|
222
|
+
}
|
223
|
+
|
224
|
+
override get getOperator(): QueryBuilderAggregateOperator {
|
225
|
+
return new QueryBuilderAggregateOperator_Percentile();
|
226
|
+
}
|
227
|
+
|
228
|
+
override get allValidationIssues(): string[] {
|
229
|
+
const validationIssues: string[] = [];
|
230
|
+
if (this.percentile === undefined || this.percentile > 100) {
|
231
|
+
validationIssues.push('Invalid Aggregation Argument for Percentile');
|
232
|
+
}
|
233
|
+
return validationIssues;
|
234
|
+
}
|
235
|
+
|
236
|
+
get hashCode(): string {
|
237
|
+
return hashArray([
|
238
|
+
QUERY_BUILDER_STATE_HASH_STRUCTURE.AGGREGATE_OPERATOR_PERCENTILE,
|
239
|
+
]);
|
240
|
+
}
|
241
|
+
}
|
@@ -1000,12 +1000,10 @@ export class QueryBuilderPostFilterState
|
|
1000
1000
|
node.condition.rightConditionValue instanceof
|
1001
1001
|
PostFilterValueSpecConditionValueState &&
|
1002
1002
|
node.condition.rightConditionValue.value instanceof InstanceValue &&
|
1003
|
-
!isValidInstanceValue(node.condition.rightConditionValue.value)
|
1004
|
-
node.condition.leftConditionValue instanceof
|
1005
|
-
QueryBuilderSimpleProjectionColumnState
|
1003
|
+
!isValidInstanceValue(node.condition.rightConditionValue.value)
|
1006
1004
|
) {
|
1007
1005
|
validationIssues.push(
|
1008
|
-
`Filter value for ${node.condition.leftConditionValue.
|
1006
|
+
`Filter value for ${node.condition.leftConditionValue.columnName} is missing or invalid`,
|
1009
1007
|
);
|
1010
1008
|
}
|
1011
1009
|
if (
|
@@ -1029,9 +1027,7 @@ export class QueryBuilderPostFilterState
|
|
1029
1027
|
node.condition.rightConditionValue instanceof
|
1030
1028
|
PostFilterValueSpecConditionValueState &&
|
1031
1029
|
node.condition.rightConditionValue.value instanceof InstanceValue &&
|
1032
|
-
!isValidInstanceValue(node.condition.rightConditionValue.value)
|
1033
|
-
node.condition.leftConditionValue instanceof
|
1034
|
-
QueryBuilderSimpleProjectionColumnState,
|
1030
|
+
!isValidInstanceValue(node.condition.rightConditionValue.value),
|
1035
1031
|
);
|
1036
1032
|
}
|
1037
1033
|
|