@elite.framework/ng.core 2.0.18 → 2.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -114,6 +114,11 @@ class BaseService {
|
|
|
114
114
|
url: this.buildUrl(id),
|
|
115
115
|
body: input,
|
|
116
116
|
}, { apiName: this.apiName });
|
|
117
|
+
patch = (id, input) => this.restService.request({
|
|
118
|
+
method: 'PATCH',
|
|
119
|
+
url: this.buildUrl(id),
|
|
120
|
+
body: input,
|
|
121
|
+
}, { apiName: this.apiName });
|
|
117
122
|
delete = (id) => this.restService.request({
|
|
118
123
|
method: 'DELETE',
|
|
119
124
|
url: this.buildUrl(id),
|
|
@@ -834,7 +839,9 @@ class QueryParser {
|
|
|
834
839
|
const params = {
|
|
835
840
|
filters: [],
|
|
836
841
|
orderBy: [],
|
|
837
|
-
groupBy: []
|
|
842
|
+
groupBy: [],
|
|
843
|
+
select: [],
|
|
844
|
+
aggregates: []
|
|
838
845
|
};
|
|
839
846
|
if (!queryString)
|
|
840
847
|
return params;
|
|
@@ -847,7 +854,13 @@ class QueryParser {
|
|
|
847
854
|
this.parseOrderBy(part.substring('$orderby='.length), params);
|
|
848
855
|
}
|
|
849
856
|
else if (part.startsWith('$groupby=')) {
|
|
850
|
-
|
|
857
|
+
this.parseGroupBy(part.substring('$groupby='.length), params);
|
|
858
|
+
}
|
|
859
|
+
else if (part.startsWith('$select=')) {
|
|
860
|
+
this.parseSelect(part.substring('$select='.length), params);
|
|
861
|
+
}
|
|
862
|
+
else if (part.startsWith('$aggregate=')) {
|
|
863
|
+
this.parseAggregate(part.substring('$aggregate='.length), params);
|
|
851
864
|
}
|
|
852
865
|
else if (part.startsWith('$top=')) {
|
|
853
866
|
params.top = Number(part.substring('$top='.length));
|
|
@@ -858,6 +871,9 @@ class QueryParser {
|
|
|
858
871
|
else if (part.startsWith('$expand=')) {
|
|
859
872
|
params.expand = part.substring('$expand='.length).split(',').map(f => f.trim());
|
|
860
873
|
}
|
|
874
|
+
else if (part.startsWith('$count=')) {
|
|
875
|
+
params.includeCount = part.substring('$count='.length).toLowerCase() === 'true';
|
|
876
|
+
}
|
|
861
877
|
}
|
|
862
878
|
return params;
|
|
863
879
|
}
|
|
@@ -872,7 +888,16 @@ class QueryParser {
|
|
|
872
888
|
parts.push(`$orderby=${encodeURIComponent(orderByStr)}`);
|
|
873
889
|
}
|
|
874
890
|
if (params.groupBy?.length) {
|
|
875
|
-
|
|
891
|
+
const groupByStr = this.buildGroupByString(params.groupBy);
|
|
892
|
+
parts.push(`$groupby=${encodeURIComponent(groupByStr)}`);
|
|
893
|
+
}
|
|
894
|
+
if (params.select?.length) {
|
|
895
|
+
const selectStr = this.buildSelectString(params.select);
|
|
896
|
+
parts.push(`$select=${encodeURIComponent(selectStr)}`);
|
|
897
|
+
}
|
|
898
|
+
if (params.aggregates?.length) {
|
|
899
|
+
const aggregateStr = this.buildAggregateString(params.aggregates);
|
|
900
|
+
parts.push(`$aggregate=${encodeURIComponent(aggregateStr)}`);
|
|
876
901
|
}
|
|
877
902
|
if (params.top !== undefined) {
|
|
878
903
|
parts.push(`$top=${params.top}`);
|
|
@@ -883,6 +908,9 @@ class QueryParser {
|
|
|
883
908
|
if (params.expand?.length) {
|
|
884
909
|
parts.push(`$expand=${encodeURIComponent(params.expand.join(','))}`);
|
|
885
910
|
}
|
|
911
|
+
if (params.includeCount !== undefined) {
|
|
912
|
+
parts.push(`$count=${params.includeCount}`);
|
|
913
|
+
}
|
|
886
914
|
return parts.join('&');
|
|
887
915
|
}
|
|
888
916
|
static buildFilterString(filters) {
|
|
@@ -909,9 +937,71 @@ class QueryParser {
|
|
|
909
937
|
}
|
|
910
938
|
}).join(' ');
|
|
911
939
|
}
|
|
940
|
+
static buildGroupByString(groupBy) {
|
|
941
|
+
return groupBy
|
|
942
|
+
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
943
|
+
.map(group => {
|
|
944
|
+
let groupStr = group.propertyName;
|
|
945
|
+
// Add display name if provided
|
|
946
|
+
if (group.displayName) {
|
|
947
|
+
groupStr += ` as ${group.displayName}`;
|
|
948
|
+
}
|
|
949
|
+
// Add metadata for UI
|
|
950
|
+
const metadata = [];
|
|
951
|
+
if (group.showTotal !== undefined) {
|
|
952
|
+
metadata.push(`showTotal:${group.showTotal}`);
|
|
953
|
+
}
|
|
954
|
+
if (group.totalBackground) {
|
|
955
|
+
metadata.push(`totalBg:${group.totalBackground}`);
|
|
956
|
+
}
|
|
957
|
+
if (group.groupHeaderBackground) {
|
|
958
|
+
metadata.push(`headerBg:${group.groupHeaderBackground}`);
|
|
959
|
+
}
|
|
960
|
+
if (metadata.length > 0) {
|
|
961
|
+
groupStr += `(${metadata.join(';')})`;
|
|
962
|
+
}
|
|
963
|
+
return groupStr;
|
|
964
|
+
})
|
|
965
|
+
.join(',');
|
|
966
|
+
}
|
|
967
|
+
static buildSelectString(select) {
|
|
968
|
+
return select
|
|
969
|
+
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
970
|
+
.map(item => {
|
|
971
|
+
let selectStr = item.propertyName;
|
|
972
|
+
// Add display name if provided
|
|
973
|
+
if (item.displayName) {
|
|
974
|
+
selectStr += ` as ${item.displayName}`;
|
|
975
|
+
}
|
|
976
|
+
// Add aggregate function if provided
|
|
977
|
+
if (item.aggregateFunction) {
|
|
978
|
+
selectStr += ` with ${item.aggregateFunction}`;
|
|
979
|
+
}
|
|
980
|
+
// Add visibility metadata
|
|
981
|
+
const metadata = [];
|
|
982
|
+
if (item.isVisible !== undefined) {
|
|
983
|
+
metadata.push(`visible:${item.isVisible}`);
|
|
984
|
+
}
|
|
985
|
+
if (metadata.length > 0) {
|
|
986
|
+
selectStr += `(${metadata.join(';')})`;
|
|
987
|
+
}
|
|
988
|
+
return selectStr;
|
|
989
|
+
})
|
|
990
|
+
.join(',');
|
|
991
|
+
}
|
|
992
|
+
static buildAggregateString(aggregates) {
|
|
993
|
+
return aggregates
|
|
994
|
+
.map(agg => {
|
|
995
|
+
let aggStr = `${agg.aggregateFunction}(${agg.propertyName})`;
|
|
996
|
+
if (agg.alias) {
|
|
997
|
+
aggStr += ` as ${agg.alias}`;
|
|
998
|
+
}
|
|
999
|
+
return aggStr;
|
|
1000
|
+
})
|
|
1001
|
+
.join(',');
|
|
1002
|
+
}
|
|
912
1003
|
static parseFilter(filterString, params) {
|
|
913
1004
|
const decodedString = decodeURIComponent(filterString);
|
|
914
|
-
// Handle individual conditions and groups
|
|
915
1005
|
const groups = [];
|
|
916
1006
|
// Split by top-level AND/OR operators
|
|
917
1007
|
const topLevelPattern = /(?:^|\s)(and|or)\s+(?=(?:[^()]*\([^()]*\))*[^()]*$)/gi;
|
|
@@ -945,19 +1035,18 @@ class QueryParser {
|
|
|
945
1035
|
}
|
|
946
1036
|
if (conditions.length > 0) {
|
|
947
1037
|
const group = {
|
|
948
|
-
logicalOperator: 'and',
|
|
1038
|
+
logicalOperator: 'and',
|
|
949
1039
|
conditions: conditions
|
|
950
1040
|
};
|
|
951
1041
|
// For groups after the first, set the groupLogicalOperator
|
|
952
1042
|
if (index > 0) {
|
|
953
1043
|
group.groupLogicalOperator = segment.operator?.toLowerCase() || 'and';
|
|
954
1044
|
}
|
|
955
|
-
//
|
|
1045
|
+
// Detect the logical operator used within the group
|
|
956
1046
|
if (conditions.length === 1 && segment.condition.includes(' or ')) {
|
|
957
1047
|
group.logicalOperator = 'or';
|
|
958
1048
|
}
|
|
959
1049
|
else if (conditions.length > 1) {
|
|
960
|
-
// Detect the logical operator used within the group
|
|
961
1050
|
group.logicalOperator = segment.condition.toLowerCase().includes(' or ') ? 'or' : 'and';
|
|
962
1051
|
}
|
|
963
1052
|
groups.push(group);
|
|
@@ -967,8 +1056,8 @@ class QueryParser {
|
|
|
967
1056
|
}
|
|
968
1057
|
static parseConditions(conditionString) {
|
|
969
1058
|
const conditions = [];
|
|
970
|
-
//
|
|
971
|
-
const pattern = /(\w+)\s+(eq|ne|gt|ge|lt|le|contains|startswith|endswith)\s+('[^']*'|\d+|true|false)/gi;
|
|
1059
|
+
// Enhanced pattern to handle more operators and complex values
|
|
1060
|
+
const pattern = /(\w+(?:\.\w+)*)\s+(eq|ne|gt|ge|lt|le|contains|startswith|endswith|in|notin)\s+('[^']*'|\[[^\]]*\]|\d+|true|false|null)/gi;
|
|
972
1061
|
let match;
|
|
973
1062
|
while ((match = pattern.exec(conditionString)) !== null) {
|
|
974
1063
|
const [, field, operator, rawValue] = match;
|
|
@@ -976,6 +1065,13 @@ class QueryParser {
|
|
|
976
1065
|
if (rawValue.startsWith("'") && rawValue.endsWith("'")) {
|
|
977
1066
|
value = rawValue.slice(1, -1).replace(/''/g, "'");
|
|
978
1067
|
}
|
|
1068
|
+
else if (rawValue.startsWith('[') && rawValue.endsWith(']')) {
|
|
1069
|
+
// Handle array values for IN/NOT IN operators
|
|
1070
|
+
value = rawValue.slice(1, -1).split(',').map(v => {
|
|
1071
|
+
const trimmed = v.trim().replace(/^'|'$/g, '');
|
|
1072
|
+
return isNaN(Number(trimmed)) ? trimmed : Number(trimmed);
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
979
1075
|
else if (!isNaN(Number(rawValue))) {
|
|
980
1076
|
value = Number(rawValue);
|
|
981
1077
|
}
|
|
@@ -985,6 +1081,9 @@ class QueryParser {
|
|
|
985
1081
|
else if (rawValue.toLowerCase() === 'false') {
|
|
986
1082
|
value = false;
|
|
987
1083
|
}
|
|
1084
|
+
else if (rawValue.toLowerCase() === 'null') {
|
|
1085
|
+
value = null;
|
|
1086
|
+
}
|
|
988
1087
|
conditions.push({
|
|
989
1088
|
field: field.trim(),
|
|
990
1089
|
operator: operator.trim().toLowerCase(),
|
|
@@ -1006,6 +1105,173 @@ class QueryParser {
|
|
|
1006
1105
|
});
|
|
1007
1106
|
}
|
|
1008
1107
|
}
|
|
1108
|
+
static parseGroupBy(groupByString, params) {
|
|
1109
|
+
const decodedString = decodeURIComponent(groupByString);
|
|
1110
|
+
const groups = decodedString.split(',');
|
|
1111
|
+
params.groupBy = groups.map((groupStr, index) => {
|
|
1112
|
+
const group = {
|
|
1113
|
+
propertyName: '',
|
|
1114
|
+
order: index
|
|
1115
|
+
};
|
|
1116
|
+
// Check for metadata in parentheses
|
|
1117
|
+
const metadataMatch = groupStr.match(/^(.*?)\((.*)\)$/);
|
|
1118
|
+
let baseStr = groupStr;
|
|
1119
|
+
let metadataStr = '';
|
|
1120
|
+
if (metadataMatch) {
|
|
1121
|
+
baseStr = metadataMatch[1];
|
|
1122
|
+
metadataStr = metadataMatch[2];
|
|
1123
|
+
}
|
|
1124
|
+
// Check for display name alias
|
|
1125
|
+
const aliasMatch = baseStr.match(/^(.*?)\s+as\s+(.*)$/);
|
|
1126
|
+
if (aliasMatch) {
|
|
1127
|
+
group.propertyName = aliasMatch[1].trim();
|
|
1128
|
+
group.displayName = aliasMatch[2].trim();
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
group.propertyName = baseStr.trim();
|
|
1132
|
+
}
|
|
1133
|
+
// Parse metadata
|
|
1134
|
+
if (metadataStr) {
|
|
1135
|
+
const metadataParts = metadataStr.split(';');
|
|
1136
|
+
metadataParts.forEach(part => {
|
|
1137
|
+
const [key, value] = part.split(':');
|
|
1138
|
+
switch (key) {
|
|
1139
|
+
case 'showTotal':
|
|
1140
|
+
group.showTotal = value.toLowerCase() === 'true';
|
|
1141
|
+
break;
|
|
1142
|
+
case 'totalBg':
|
|
1143
|
+
group.totalBackground = value;
|
|
1144
|
+
break;
|
|
1145
|
+
case 'headerBg':
|
|
1146
|
+
group.groupHeaderBackground = value;
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
return group;
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
static parseSelect(selectString, params) {
|
|
1155
|
+
const decodedString = decodeURIComponent(selectString);
|
|
1156
|
+
const items = decodedString.split(',');
|
|
1157
|
+
params.select = items.map((itemStr, index) => {
|
|
1158
|
+
const item = {
|
|
1159
|
+
propertyName: '',
|
|
1160
|
+
isVisible: true,
|
|
1161
|
+
order: index
|
|
1162
|
+
};
|
|
1163
|
+
// Check for metadata in parentheses
|
|
1164
|
+
const metadataMatch = itemStr.match(/^(.*?)\((.*)\)$/);
|
|
1165
|
+
let baseStr = itemStr;
|
|
1166
|
+
let metadataStr = '';
|
|
1167
|
+
if (metadataMatch) {
|
|
1168
|
+
baseStr = metadataMatch[1];
|
|
1169
|
+
metadataStr = metadataMatch[2];
|
|
1170
|
+
}
|
|
1171
|
+
// Check for display name alias and aggregate function
|
|
1172
|
+
const aliasMatch = baseStr.match(/^(.*?)(?:\s+as\s+(.*?))?(?:\s+with\s+(\w+))?$/);
|
|
1173
|
+
if (aliasMatch) {
|
|
1174
|
+
item.propertyName = aliasMatch[1].trim();
|
|
1175
|
+
if (aliasMatch[2]) {
|
|
1176
|
+
item.displayName = aliasMatch[2].trim();
|
|
1177
|
+
}
|
|
1178
|
+
if (aliasMatch[3]) {
|
|
1179
|
+
item.aggregateFunction = aliasMatch[3].trim();
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
item.propertyName = baseStr.trim();
|
|
1184
|
+
}
|
|
1185
|
+
// Parse metadata
|
|
1186
|
+
if (metadataStr) {
|
|
1187
|
+
const metadataParts = metadataStr.split(';');
|
|
1188
|
+
metadataParts.forEach(part => {
|
|
1189
|
+
const [key, value] = part.split(':');
|
|
1190
|
+
if (key === 'visible') {
|
|
1191
|
+
item.isVisible = value.toLowerCase() === 'true';
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
return item;
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
static parseAggregate(aggregateString, params) {
|
|
1199
|
+
const decodedString = decodeURIComponent(aggregateString);
|
|
1200
|
+
const aggregates = decodedString.split(',');
|
|
1201
|
+
params.aggregates = aggregates.map(aggStr => {
|
|
1202
|
+
const agg = {
|
|
1203
|
+
propertyName: '',
|
|
1204
|
+
aggregateFunction: ''
|
|
1205
|
+
};
|
|
1206
|
+
// Match pattern: function(property) as alias
|
|
1207
|
+
const match = aggStr.match(/^(\w+)\((\w+)\)(?:\s+as\s+(\w+))?$/);
|
|
1208
|
+
if (match) {
|
|
1209
|
+
agg.aggregateFunction = match[1];
|
|
1210
|
+
agg.propertyName = match[2];
|
|
1211
|
+
if (match[3]) {
|
|
1212
|
+
agg.alias = match[3];
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return agg;
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
// Helper method to convert QueryParameters to ODataQueryParameters (C# equivalent)
|
|
1219
|
+
static toODataQueryParameters(params) {
|
|
1220
|
+
return {
|
|
1221
|
+
Filters: params.filters.map(group => ({
|
|
1222
|
+
LogicalOperator: group.logicalOperator,
|
|
1223
|
+
GroupLogicalOperator: group.groupLogicalOperator,
|
|
1224
|
+
Conditions: group.conditions.map(cond => ({
|
|
1225
|
+
Field: cond.field,
|
|
1226
|
+
Operator: cond.operator,
|
|
1227
|
+
Value: cond.value
|
|
1228
|
+
}))
|
|
1229
|
+
})),
|
|
1230
|
+
OrderBy: params.orderBy?.map(order => ({
|
|
1231
|
+
Field: order.field,
|
|
1232
|
+
Direction: order.direction
|
|
1233
|
+
})) || [],
|
|
1234
|
+
GroupBy: params.groupBy?.map(group => ({
|
|
1235
|
+
PropertyName: group.propertyName,
|
|
1236
|
+
DisplayName: group.displayName,
|
|
1237
|
+
ShowTotal: group.showTotal ?? true,
|
|
1238
|
+
TotalBackground: group.totalBackground,
|
|
1239
|
+
GroupHeaderBackground: group.groupHeaderBackground,
|
|
1240
|
+
Order: group.order
|
|
1241
|
+
})) || [],
|
|
1242
|
+
Select: params.select?.map(sel => ({
|
|
1243
|
+
PropertyName: sel.propertyName,
|
|
1244
|
+
DisplayName: sel.displayName,
|
|
1245
|
+
AggregateFunction: sel.aggregateFunction,
|
|
1246
|
+
IsVisible: sel.isVisible ?? true,
|
|
1247
|
+
Order: sel.order
|
|
1248
|
+
})) || [],
|
|
1249
|
+
Aggregates: params.aggregates?.map(agg => ({
|
|
1250
|
+
PropertyName: agg.propertyName,
|
|
1251
|
+
AggregateFunction: agg.aggregateFunction,
|
|
1252
|
+
Alias: agg.alias
|
|
1253
|
+
})) || [],
|
|
1254
|
+
Top: params.top,
|
|
1255
|
+
Skip: params.skip,
|
|
1256
|
+
Expand: params.expand,
|
|
1257
|
+
IncludeCount: params.includeCount
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
// Helper method to create query parameters from UI model
|
|
1261
|
+
static fromUIModel(model) {
|
|
1262
|
+
const params = {
|
|
1263
|
+
filters: model.advancedFilters || [],
|
|
1264
|
+
orderBy: model.sorting || [],
|
|
1265
|
+
groupBy: model.grouping || [],
|
|
1266
|
+
select: model.columns || [],
|
|
1267
|
+
aggregates: model.aggregates || [],
|
|
1268
|
+
top: model.pagination?.top,
|
|
1269
|
+
skip: model.pagination?.skip,
|
|
1270
|
+
expand: model.expand,
|
|
1271
|
+
includeCount: model.pagination?.includeCount
|
|
1272
|
+
};
|
|
1273
|
+
return params;
|
|
1274
|
+
}
|
|
1009
1275
|
}
|
|
1010
1276
|
|
|
1011
1277
|
/**
|