@elite.framework/ng.core 2.0.17 → 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),
@@ -829,9 +834,449 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImpor
829
834
  args: [{ providedIn: 'root' }]
830
835
  }] });
831
836
 
837
+ class QueryParser {
838
+ static parse(queryString) {
839
+ const params = {
840
+ filters: [],
841
+ orderBy: [],
842
+ groupBy: [],
843
+ select: [],
844
+ aggregates: []
845
+ };
846
+ if (!queryString)
847
+ return params;
848
+ const queryParts = queryString.split('&');
849
+ for (const part of queryParts) {
850
+ if (part.startsWith('$filter=')) {
851
+ this.parseFilter(part.substring('$filter='.length), params);
852
+ }
853
+ else if (part.startsWith('$orderby=')) {
854
+ this.parseOrderBy(part.substring('$orderby='.length), params);
855
+ }
856
+ else if (part.startsWith('$groupby=')) {
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);
864
+ }
865
+ else if (part.startsWith('$top=')) {
866
+ params.top = Number(part.substring('$top='.length));
867
+ }
868
+ else if (part.startsWith('$skip=')) {
869
+ params.skip = Number(part.substring('$skip='.length));
870
+ }
871
+ else if (part.startsWith('$expand=')) {
872
+ params.expand = part.substring('$expand='.length).split(',').map(f => f.trim());
873
+ }
874
+ else if (part.startsWith('$count=')) {
875
+ params.includeCount = part.substring('$count='.length).toLowerCase() === 'true';
876
+ }
877
+ }
878
+ return params;
879
+ }
880
+ static toString(params) {
881
+ const parts = [];
882
+ if (params.filters?.length) {
883
+ const filterStr = this.buildFilterString(params.filters);
884
+ parts.push(`$filter=${encodeURIComponent(filterStr)}`);
885
+ }
886
+ if (params.orderBy?.length) {
887
+ const orderByStr = params.orderBy.map(o => `${o.field} ${o.direction}`).join(',');
888
+ parts.push(`$orderby=${encodeURIComponent(orderByStr)}`);
889
+ }
890
+ if (params.groupBy?.length) {
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)}`);
901
+ }
902
+ if (params.top !== undefined) {
903
+ parts.push(`$top=${params.top}`);
904
+ }
905
+ if (params.skip !== undefined) {
906
+ parts.push(`$skip=${params.skip}`);
907
+ }
908
+ if (params.expand?.length) {
909
+ parts.push(`$expand=${encodeURIComponent(params.expand.join(','))}`);
910
+ }
911
+ if (params.includeCount !== undefined) {
912
+ parts.push(`$count=${params.includeCount}`);
913
+ }
914
+ return parts.join('&');
915
+ }
916
+ static buildFilterString(filters) {
917
+ return filters.map((group, index) => {
918
+ const groupStr = group.conditions
919
+ .map(condition => {
920
+ let val = condition.value;
921
+ if (typeof val === 'string') {
922
+ val = `'${val.replace(/'/g, "''")}'`;
923
+ }
924
+ else if (typeof val === 'boolean') {
925
+ val = val ? 'true' : 'false';
926
+ }
927
+ return `${condition.field} ${condition.operator} ${val}`;
928
+ })
929
+ .join(` ${group.logicalOperator} `);
930
+ // For the first group, no groupLogicalOperator is needed
931
+ if (index === 0) {
932
+ return group.conditions.length > 1 ? `(${groupStr})` : groupStr;
933
+ }
934
+ else {
935
+ const joinOp = group.groupLogicalOperator || 'and';
936
+ return group.conditions.length > 1 ? `${joinOp} (${groupStr})` : `${joinOp} ${groupStr}`;
937
+ }
938
+ }).join(' ');
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
+ }
1003
+ static parseFilter(filterString, params) {
1004
+ const decodedString = decodeURIComponent(filterString);
1005
+ const groups = [];
1006
+ // Split by top-level AND/OR operators
1007
+ const topLevelPattern = /(?:^|\s)(and|or)\s+(?=(?:[^()]*\([^()]*\))*[^()]*$)/gi;
1008
+ const segments = [];
1009
+ let lastIndex = 0;
1010
+ let match;
1011
+ while ((match = topLevelPattern.exec(decodedString)) !== null) {
1012
+ const operator = match[1];
1013
+ const segment = decodedString.substring(lastIndex, match.index).trim();
1014
+ if (segment) {
1015
+ segments.push({ condition: segment, operator });
1016
+ }
1017
+ lastIndex = match.index + match[0].length;
1018
+ }
1019
+ // Add the last segment
1020
+ const lastSegment = decodedString.substring(lastIndex).trim();
1021
+ if (lastSegment) {
1022
+ segments.push({ condition: lastSegment, operator: undefined });
1023
+ }
1024
+ // Parse each segment
1025
+ segments.forEach((segment, index) => {
1026
+ let conditions = [];
1027
+ // Check if it's a group with parentheses
1028
+ if (segment.condition.startsWith('(') && segment.condition.endsWith(')')) {
1029
+ const innerCondition = segment.condition.slice(1, -1).trim();
1030
+ conditions = this.parseConditions(innerCondition);
1031
+ }
1032
+ else {
1033
+ // Individual condition
1034
+ conditions = this.parseConditions(segment.condition);
1035
+ }
1036
+ if (conditions.length > 0) {
1037
+ const group = {
1038
+ logicalOperator: 'and',
1039
+ conditions: conditions
1040
+ };
1041
+ // For groups after the first, set the groupLogicalOperator
1042
+ if (index > 0) {
1043
+ group.groupLogicalOperator = segment.operator?.toLowerCase() || 'and';
1044
+ }
1045
+ // Detect the logical operator used within the group
1046
+ if (conditions.length === 1 && segment.condition.includes(' or ')) {
1047
+ group.logicalOperator = 'or';
1048
+ }
1049
+ else if (conditions.length > 1) {
1050
+ group.logicalOperator = segment.condition.toLowerCase().includes(' or ') ? 'or' : 'and';
1051
+ }
1052
+ groups.push(group);
1053
+ }
1054
+ });
1055
+ params.filters = groups;
1056
+ }
1057
+ static parseConditions(conditionString) {
1058
+ const conditions = [];
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;
1061
+ let match;
1062
+ while ((match = pattern.exec(conditionString)) !== null) {
1063
+ const [, field, operator, rawValue] = match;
1064
+ let value = rawValue.trim();
1065
+ if (rawValue.startsWith("'") && rawValue.endsWith("'")) {
1066
+ value = rawValue.slice(1, -1).replace(/''/g, "'");
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
+ }
1075
+ else if (!isNaN(Number(rawValue))) {
1076
+ value = Number(rawValue);
1077
+ }
1078
+ else if (rawValue.toLowerCase() === 'true') {
1079
+ value = true;
1080
+ }
1081
+ else if (rawValue.toLowerCase() === 'false') {
1082
+ value = false;
1083
+ }
1084
+ else if (rawValue.toLowerCase() === 'null') {
1085
+ value = null;
1086
+ }
1087
+ conditions.push({
1088
+ field: field.trim(),
1089
+ operator: operator.trim().toLowerCase(),
1090
+ value
1091
+ });
1092
+ }
1093
+ return conditions;
1094
+ }
1095
+ static parseOrderBy(orderByString, params) {
1096
+ const decodedString = decodeURIComponent(orderByString);
1097
+ const clauses = decodedString.split(',');
1098
+ for (const clause of clauses) {
1099
+ const parts = clause.trim().split(/\s+/);
1100
+ const field = parts[0];
1101
+ const direction = parts[1]?.toLowerCase() || 'asc';
1102
+ params.orderBy?.push({
1103
+ field,
1104
+ direction
1105
+ });
1106
+ }
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
+ }
1275
+ }
1276
+
832
1277
  /**
833
1278
  * Generated bundle index. Do not edit.
834
1279
  */
835
1280
 
836
- export { BaseService, GenericService, IdParserService, LogLevel, LoggerService, NgxPermissionsGuard, PermissionsService, REQUEST, RestService, SsrCookieService, SwalService, isUndefinedOrEmptyString, ngxPermissionsGuard };
1281
+ export { BaseService, GenericService, IdParserService, LogLevel, LoggerService, NgxPermissionsGuard, PermissionsService, QueryParser, REQUEST, RestService, SsrCookieService, SwalService, isUndefinedOrEmptyString, ngxPermissionsGuard };
837
1282
  //# sourceMappingURL=elite.framework-ng.core-services.mjs.map