@slickgrid-universal/odata 5.14.0 → 9.0.2

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.
Files changed (67) hide show
  1. package/dist/index.d.ts.map +1 -0
  2. package/dist/index.js.map +1 -0
  3. package/dist/interfaces/index.d.ts.map +1 -0
  4. package/dist/{esm/interfaces → interfaces}/index.js.map +1 -1
  5. package/dist/interfaces/odataOption.interface.d.ts.map +1 -0
  6. package/dist/interfaces/odataOption.interface.js.map +1 -0
  7. package/dist/interfaces/odataServiceApi.interface.d.ts.map +1 -0
  8. package/dist/interfaces/odataServiceApi.interface.js.map +1 -0
  9. package/dist/interfaces/odataSortingOption.interface.d.ts.map +1 -0
  10. package/dist/interfaces/odataSortingOption.interface.js.map +1 -0
  11. package/dist/{types/services → services}/grid-odata.service.d.ts +1 -1
  12. package/dist/services/grid-odata.service.d.ts.map +1 -0
  13. package/dist/{esm/services → services}/grid-odata.service.js +14 -14
  14. package/dist/services/grid-odata.service.js.map +1 -0
  15. package/dist/services/index.d.ts.map +1 -0
  16. package/dist/services/index.js.map +1 -0
  17. package/dist/services/odataQueryBuilder.service.d.ts.map +1 -0
  18. package/dist/{esm/services → services}/odataQueryBuilder.service.js +2 -2
  19. package/dist/services/odataQueryBuilder.service.js.map +1 -0
  20. package/package.json +9 -11
  21. package/src/services/grid-odata.service.ts +14 -14
  22. package/src/services/odataQueryBuilder.service.ts +2 -2
  23. package/dist/cjs/index.js +0 -8
  24. package/dist/cjs/index.js.map +0 -1
  25. package/dist/cjs/interfaces/index.js +0 -3
  26. package/dist/cjs/interfaces/index.js.map +0 -1
  27. package/dist/cjs/interfaces/odataOption.interface.js +0 -3
  28. package/dist/cjs/interfaces/odataOption.interface.js.map +0 -1
  29. package/dist/cjs/interfaces/odataServiceApi.interface.js +0 -3
  30. package/dist/cjs/interfaces/odataServiceApi.interface.js.map +0 -1
  31. package/dist/cjs/interfaces/odataSortingOption.interface.js +0 -3
  32. package/dist/cjs/interfaces/odataSortingOption.interface.js.map +0 -1
  33. package/dist/cjs/services/grid-odata.service.js +0 -649
  34. package/dist/cjs/services/grid-odata.service.js.map +0 -1
  35. package/dist/cjs/services/index.js +0 -19
  36. package/dist/cjs/services/index.js.map +0 -1
  37. package/dist/cjs/services/odataQueryBuilder.service.js +0 -209
  38. package/dist/cjs/services/odataQueryBuilder.service.js.map +0 -1
  39. package/dist/esm/index.js.map +0 -1
  40. package/dist/esm/interfaces/odataOption.interface.js.map +0 -1
  41. package/dist/esm/interfaces/odataServiceApi.interface.js.map +0 -1
  42. package/dist/esm/interfaces/odataSortingOption.interface.js.map +0 -1
  43. package/dist/esm/services/grid-odata.service.js.map +0 -1
  44. package/dist/esm/services/index.js.map +0 -1
  45. package/dist/esm/services/odataQueryBuilder.service.js.map +0 -1
  46. package/dist/tsconfig.tsbuildinfo +0 -1
  47. package/dist/types/index.d.ts.map +0 -1
  48. package/dist/types/interfaces/index.d.ts.map +0 -1
  49. package/dist/types/interfaces/odataOption.interface.d.ts.map +0 -1
  50. package/dist/types/interfaces/odataServiceApi.interface.d.ts.map +0 -1
  51. package/dist/types/interfaces/odataSortingOption.interface.d.ts.map +0 -1
  52. package/dist/types/services/grid-odata.service.d.ts.map +0 -1
  53. package/dist/types/services/index.d.ts.map +0 -1
  54. package/dist/types/services/odataQueryBuilder.service.d.ts.map +0 -1
  55. /package/dist/{types/index.d.ts → index.d.ts} +0 -0
  56. /package/dist/{esm/index.js → index.js} +0 -0
  57. /package/dist/{types/interfaces → interfaces}/index.d.ts +0 -0
  58. /package/dist/{esm/interfaces → interfaces}/index.js +0 -0
  59. /package/dist/{types/interfaces → interfaces}/odataOption.interface.d.ts +0 -0
  60. /package/dist/{esm/interfaces → interfaces}/odataOption.interface.js +0 -0
  61. /package/dist/{types/interfaces → interfaces}/odataServiceApi.interface.d.ts +0 -0
  62. /package/dist/{esm/interfaces → interfaces}/odataServiceApi.interface.js +0 -0
  63. /package/dist/{types/interfaces → interfaces}/odataSortingOption.interface.d.ts +0 -0
  64. /package/dist/{esm/interfaces → interfaces}/odataSortingOption.interface.js +0 -0
  65. /package/dist/{types/services → services}/index.d.ts +0 -0
  66. /package/dist/{esm/services → services}/index.js +0 -0
  67. /package/dist/{types/services → services}/odataQueryBuilder.service.d.ts +0 -0
@@ -1,649 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GridOdataService = void 0;
4
- const common_1 = require("@slickgrid-universal/common");
5
- const utils_1 = require("@slickgrid-universal/utils");
6
- const odataQueryBuilder_service_js_1 = require("./odataQueryBuilder.service.js");
7
- const DEFAULT_ITEMS_PER_PAGE = 25;
8
- const DEFAULT_PAGE_SIZE = 20;
9
- class GridOdataService {
10
- /** Getter for the Column Definitions */
11
- get columnDefinitions() {
12
- return this._columnDefinitions;
13
- }
14
- /** Getter for the Odata Service */
15
- get odataService() {
16
- return this._odataService;
17
- }
18
- /** Getter for the Grid Options pulled through the Grid Object */
19
- get _gridOptions() {
20
- return this._grid?.getOptions() ?? {};
21
- }
22
- constructor() {
23
- this._currentFilters = [];
24
- this._currentPagination = null;
25
- this._currentSorters = [];
26
- this._columnDefinitions = [];
27
- this.defaultOptions = {
28
- top: DEFAULT_ITEMS_PER_PAGE,
29
- orderBy: '',
30
- caseType: common_1.CaseType.pascalCase,
31
- };
32
- this._odataService = new odataQueryBuilder_service_js_1.OdataQueryBuilderService();
33
- }
34
- init(serviceOptions, pagination, grid, sharedService) {
35
- this._grid = grid;
36
- const mergedOptions = { ...this.defaultOptions, ...serviceOptions };
37
- // unless user specifically set "enablePagination" to False, we'll add "top" property for the pagination in every other cases
38
- if (!this._gridOptions.enablePagination && !mergedOptions?.infiniteScroll) {
39
- // save current pagination as Page 1 and page size as "top"
40
- this._odataService.options = { ...mergedOptions, top: undefined };
41
- this._currentPagination = null;
42
- }
43
- else {
44
- const topOption = mergedOptions.infiniteScroll?.fetchSize ?? pagination?.pageSize ?? this.defaultOptions.top;
45
- this._odataService.options = { ...mergedOptions, top: topOption };
46
- this._currentPagination = {
47
- pageNumber: 1,
48
- pageSize: this._odataService.options.top || this.defaultOptions.top || DEFAULT_PAGE_SIZE,
49
- };
50
- }
51
- this.options = this._odataService.options;
52
- this.pagination = pagination;
53
- if (grid?.getColumns) {
54
- const tmpColumnDefinitions = sharedService?.allColumns ?? grid.getColumns() ?? [];
55
- this._columnDefinitions = tmpColumnDefinitions.filter((column) => !column.excludeFromQuery);
56
- }
57
- this._odataService.columnDefinitions = this._columnDefinitions;
58
- this._odataService.datasetIdPropName = this._gridOptions.datasetIdPropertyName || 'id';
59
- }
60
- buildQuery() {
61
- return this._odataService.buildQuery();
62
- }
63
- postProcess(processResult) {
64
- const odataVersion = this._odataService.options.version ?? 2;
65
- if (this.pagination && this._odataService.options.enableCount) {
66
- const countExtractor = (this._odataService.options.countExtractor ?? odataVersion >= 4)
67
- ? (r) => r?.['@odata.count']
68
- : odataVersion === 3
69
- ? (r) => r?.['__count']
70
- : (r) => r?.d?.['__count'];
71
- const count = countExtractor(processResult);
72
- if (typeof count === 'number') {
73
- this.pagination.totalItems = count;
74
- }
75
- }
76
- if (this._odataService.options.enableExpand) {
77
- const datasetExtractor = (this._odataService.options.datasetExtractor ?? odataVersion >= 4)
78
- ? (r) => r?.value
79
- : odataVersion === 3
80
- ? (r) => r?.results
81
- : (r) => r?.d?.results;
82
- const dataset = datasetExtractor(processResult);
83
- if (Array.isArray(dataset)) {
84
- // Flatten navigation fields (fields containing /) in the dataset (regardless of enableExpand).
85
- // E.g. given columndefinition 'product/name' and dataset [{id: 1,product:{'name':'flowers'}}], then flattens to [{id:1,'product/name':'flowers'}]
86
- const navigationFields = new Set(this._columnDefinitions.flatMap((x) => x.fields ?? [x.field]).filter((x) => x.includes('/')));
87
- if (navigationFields.size > 0) {
88
- const navigations = new Set();
89
- for (const item of dataset) {
90
- for (const field of navigationFields) {
91
- const names = field.split('/');
92
- const navigation = names[0];
93
- navigations.add(navigation);
94
- let val = item[navigation];
95
- for (let i = 1; i < names.length; i++) {
96
- const mappedName = names[i];
97
- if (val && typeof val === 'object' && mappedName in val) {
98
- val = val[mappedName];
99
- }
100
- }
101
- item[field] = val;
102
- }
103
- // Remove navigation objects from the dataset to free memory and make sure we never work with them.
104
- for (const navigation of navigations) {
105
- if (typeof item[navigation] === 'object') {
106
- delete item[navigation];
107
- }
108
- }
109
- }
110
- }
111
- }
112
- }
113
- }
114
- clearFilters() {
115
- this._currentFilters = [];
116
- this.updateFilters([]);
117
- }
118
- clearSorters() {
119
- this._currentSorters = [];
120
- this.updateSorters([]);
121
- }
122
- updateOptions(serviceOptions) {
123
- this.options = { ...this.options, ...serviceOptions };
124
- this._odataService.options = this.options;
125
- }
126
- removeColumnFilter(fieldName) {
127
- this._odataService.removeColumnFilter(fieldName);
128
- }
129
- /** Get the Filters that are currently used by the grid */
130
- getCurrentFilters() {
131
- return this._currentFilters;
132
- }
133
- /** Get the Pagination that is currently used by the grid */
134
- getCurrentPagination() {
135
- return this._currentPagination;
136
- }
137
- /** Get the Sorters that are currently used by the grid */
138
- getCurrentSorters() {
139
- return this._currentSorters;
140
- }
141
- /**
142
- * Mapper for mathematical operators (ex.: <= is "le", > is "gt")
143
- * @param string operator
144
- * @returns string map
145
- */
146
- mapOdataOperator(operator) {
147
- let map = '';
148
- switch (operator) {
149
- case '<':
150
- map = 'lt';
151
- break;
152
- case '<=':
153
- map = 'le';
154
- break;
155
- case '>':
156
- map = 'gt';
157
- break;
158
- case '>=':
159
- map = 'ge';
160
- break;
161
- case '<>':
162
- case '!=':
163
- map = 'ne';
164
- break;
165
- case '=':
166
- case '==':
167
- default:
168
- map = 'eq';
169
- break;
170
- }
171
- return map;
172
- }
173
- /*
174
- * Reset the pagination options
175
- */
176
- resetPaginationOptions() {
177
- this._odataService.updateOptions({
178
- skip: 0,
179
- });
180
- }
181
- saveColumnFilter(fieldName, value, terms) {
182
- this._odataService.saveColumnFilter(fieldName, value, terms);
183
- }
184
- /*
185
- * FILTERING
186
- */
187
- processOnFilterChanged(_event, args) {
188
- const gridOptions = this._gridOptions;
189
- const backendApi = gridOptions.backendServiceApi;
190
- if (backendApi === undefined) {
191
- throw new Error('Something went wrong in the GridOdataService, "backendServiceApi" is not initialized');
192
- }
193
- // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
194
- this._currentFilters = this.castFilterToColumnFilters(args.columnFilters);
195
- if (!args || !args.grid) {
196
- throw new Error('Something went wrong when trying create the GridOdataService, it seems that "args" is not populated correctly');
197
- }
198
- // loop through all columns to inspect filters & set the query
199
- this.updateFilters(args.columnFilters);
200
- this.resetPaginationOptions();
201
- return this._odataService.buildQuery();
202
- }
203
- /*
204
- * PAGINATION
205
- */
206
- processOnPaginationChanged(_event, args) {
207
- const pageSize = +(this.options?.infiniteScroll?.fetchSize ||
208
- args.pageSize ||
209
- (this.pagination ? this.pagination.pageSize : DEFAULT_PAGE_SIZE));
210
- this.updatePagination(args.newPage, pageSize);
211
- // build the OData query which we will use in the WebAPI callback
212
- return this._odataService.buildQuery();
213
- }
214
- /*
215
- * SORTING
216
- */
217
- processOnSortChanged(_event, args) {
218
- const sortColumns = args.multiColumnSort
219
- ? args.sortCols
220
- : new Array({
221
- columnId: args.sortCol?.id ?? '',
222
- sortCol: args.sortCol,
223
- sortAsc: args.sortAsc,
224
- });
225
- // loop through all columns to inspect sorters & set the query
226
- this.updateSorters(sortColumns);
227
- // when using infinite scroll, we need to go back to 1st page
228
- if (this.options?.infiniteScroll) {
229
- this._odataService.updateOptions({ skip: undefined });
230
- }
231
- // build the OData query which we will use in the WebAPI callback
232
- return this._odataService.buildQuery();
233
- }
234
- /**
235
- * loop through all columns to inspect filters & update backend service filters
236
- * @param columnFilters
237
- */
238
- updateFilters(columnFilters, isUpdatedByPresetOrDynamically) {
239
- let searchBy = '';
240
- const searchByArray = [];
241
- const odataVersion = this._odataService.options.version ?? 2;
242
- // on filter preset load, we need to keep current filters
243
- if (isUpdatedByPresetOrDynamically) {
244
- this._currentFilters = this.castFilterToColumnFilters(columnFilters);
245
- }
246
- // loop through all columns to inspect filters
247
- for (const columnId in columnFilters) {
248
- if (columnFilters.hasOwnProperty(columnId)) {
249
- const columnFilter = columnFilters[columnId];
250
- // if user defined some "presets", then we need to find the filters from the column definitions instead
251
- let columnDef;
252
- if (isUpdatedByPresetOrDynamically && Array.isArray(this._columnDefinitions)) {
253
- columnDef = this._columnDefinitions.find((column) => column.id === columnFilter.columnId);
254
- }
255
- else {
256
- columnDef = columnFilter.columnDef;
257
- }
258
- if (!columnDef) {
259
- throw new Error('[GridOData Service]: Something went wrong in trying to get the column definition of the specified filter (or preset filters). Did you make a typo on the filter columnId?');
260
- }
261
- let fieldName = columnDef.filter?.queryField || columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || columnDef.name || '';
262
- if (fieldName instanceof HTMLElement) {
263
- fieldName = (0, utils_1.stripTags)(fieldName.innerHTML);
264
- }
265
- const fieldType = columnDef.type || common_1.FieldType.string;
266
- let searchTerms = (columnFilter?.searchTerms ? [...columnFilter.searchTerms] : null) || [];
267
- let fieldSearchValue = Array.isArray(searchTerms) && searchTerms.length === 1 ? searchTerms[0] : '';
268
- if (typeof fieldSearchValue === 'undefined') {
269
- fieldSearchValue = '';
270
- }
271
- if (!fieldName) {
272
- throw new Error(`GridOData filter could not find the field name to query the search, your column definition must include a valid "field" or "name" (optionally you can also use the "queryfield").`);
273
- }
274
- if (this._odataService.options.useVerbatimSearchTerms || columnFilter.verbatimSearchTerms) {
275
- searchByArray.push(`${fieldName} ${columnFilter.operator} ${JSON.stringify(columnFilter.searchTerms)}`.trim());
276
- continue;
277
- }
278
- fieldSearchValue = fieldSearchValue === undefined || fieldSearchValue === null ? '' : `${fieldSearchValue}`; // make sure it's a string
279
- // run regex to find possible filter operators unless the user disabled the feature
280
- const autoParseInputFilterOperator = columnDef.autoParseInputFilterOperator ?? this._gridOptions.autoParseInputFilterOperator;
281
- // group (2): comboStartsWith, (3): comboEndsWith, (4): Operator, (1 or 5): searchValue, (6): last char is '*' (meaning starts with, ex.: abc*)
282
- const matches = autoParseInputFilterOperator !== false
283
- ? fieldSearchValue.match(/^((.*[^\\*\r\n])[*]{1}(.*[^*\r\n]))|^([<>!=*]{0,2})(.*[^<>!=*])([*]?)$/) || []
284
- : [fieldSearchValue, '', '', '', '', fieldSearchValue, ''];
285
- const comboStartsWith = matches?.[2] || '';
286
- const comboEndsWith = matches?.[3] || '';
287
- let operator = columnFilter.operator || matches?.[4];
288
- let searchValue = matches?.[1] || matches?.[5] || '';
289
- const lastValueChar = matches?.[6] || operator === '*z' || operator === common_1.OperatorType.endsWith ? '*' : '';
290
- const bypassOdataQuery = columnFilter.bypassBackendQuery || false;
291
- // no need to query if search value is empty
292
- if (fieldName && searchValue === '' && searchTerms.length <= 1) {
293
- this.removeColumnFilter((0, utils_1.getHtmlStringOutput)(fieldName));
294
- continue;
295
- }
296
- // StartsWith + EndsWith combo
297
- if (comboStartsWith && comboEndsWith) {
298
- searchTerms = [comboStartsWith, comboEndsWith];
299
- operator = common_1.OperatorType.startsWithEndsWith;
300
- }
301
- else if (Array.isArray(searchTerms) &&
302
- searchTerms.length === 1 &&
303
- typeof searchTerms[0] === 'string' &&
304
- searchTerms[0].indexOf('..') >= 0) {
305
- // range filter
306
- if (operator !== common_1.OperatorType.rangeInclusive && operator !== common_1.OperatorType.rangeExclusive) {
307
- operator = this._gridOptions.defaultFilterRangeOperator ?? common_1.OperatorType.rangeInclusive;
308
- }
309
- searchTerms = searchTerms[0].split('..', 2);
310
- if (searchTerms[0] === '') {
311
- operator = operator === common_1.OperatorType.rangeInclusive ? '<=' : operator === common_1.OperatorType.rangeExclusive ? '<' : operator;
312
- searchTerms = searchTerms.slice(1);
313
- searchValue = searchTerms[0];
314
- }
315
- else if (searchTerms[1] === '') {
316
- operator = operator === common_1.OperatorType.rangeInclusive ? '>=' : operator === common_1.OperatorType.rangeExclusive ? '>' : operator;
317
- searchTerms = searchTerms.slice(0, 1);
318
- searchValue = searchTerms[0];
319
- }
320
- }
321
- // if we didn't find an Operator but we have a Column Operator inside the Filter (DOM Element), we should use its default Operator
322
- // multipleSelect is "IN", while singleSelect is "EQ", else don't map any operator
323
- if (!operator && columnDef.filter) {
324
- operator = columnDef.filter.operator;
325
- }
326
- // No operator and 2 search terms should lead to default range operator.
327
- if (!operator && Array.isArray(searchTerms) && searchTerms.length === 2 && searchTerms[0] && searchTerms[1]) {
328
- operator = this._gridOptions.defaultFilterRangeOperator;
329
- }
330
- // Range with 1 searchterm should lead to equals for a date field.
331
- if ((operator === common_1.OperatorType.rangeInclusive || operator === common_1.OperatorType.rangeExclusive) &&
332
- Array.isArray(searchTerms) &&
333
- searchTerms.length === 1 &&
334
- fieldType === common_1.FieldType.date) {
335
- operator = common_1.OperatorType.equal;
336
- }
337
- // if we still don't have an operator find the proper Operator to use according to field type
338
- if (!operator) {
339
- operator = (0, common_1.mapOperatorByFieldType)(fieldType);
340
- }
341
- // extra query arguments
342
- if (bypassOdataQuery) {
343
- // push to our temp array and also trim white spaces
344
- if (fieldName) {
345
- this.saveColumnFilter((0, utils_1.getHtmlStringOutput)(fieldName), fieldSearchValue, searchTerms);
346
- }
347
- }
348
- else {
349
- // Normalize all search values
350
- searchValue = this.normalizeSearchValue(fieldType, searchValue, odataVersion);
351
- if (Array.isArray(searchTerms)) {
352
- searchTerms.forEach((_part, index) => {
353
- searchTerms[index] = this.normalizeSearchValue(fieldType, searchTerms[index], odataVersion);
354
- });
355
- }
356
- searchBy = '';
357
- // titleCase the fieldName so that it matches the WebApi names
358
- if (this._odataService.options.caseType === common_1.CaseType.pascalCase) {
359
- fieldName = (0, utils_1.titleCase)((0, utils_1.getHtmlStringOutput)(fieldName || ''));
360
- }
361
- let filterQueryOverride = undefined;
362
- if (typeof this._odataService.options.filterQueryOverride === 'function') {
363
- filterQueryOverride = this._odataService.options.filterQueryOverride({
364
- fieldName: (0, utils_1.getHtmlStringOutput)(fieldName),
365
- columnDef,
366
- operator,
367
- columnFilterOperator: columnFilter.operator,
368
- searchValues: searchTerms,
369
- grid: this._grid,
370
- });
371
- }
372
- if (filterQueryOverride !== undefined) {
373
- searchBy = filterQueryOverride;
374
- }
375
- else if (operator === common_1.OperatorType.startsWithEndsWith && Array.isArray(searchTerms) && searchTerms.length === 2) {
376
- const tmpSearchTerms = [];
377
- const [sw, ew] = searchTerms;
378
- // add 2 conditions (StartsWith A + EndsWith B) to the search array
379
- tmpSearchTerms.push(`startswith(${fieldName}, ${sw})`);
380
- tmpSearchTerms.push(`endswith(${fieldName}, ${ew})`);
381
- searchBy = tmpSearchTerms.join(' and ');
382
- }
383
- else if (searchTerms?.length > 1 &&
384
- (operator === 'IN' || operator === 'NIN' || operator === 'NOTIN' || operator === 'NOT IN' || operator === 'NOT_IN')) {
385
- // when having more than 1 search term (then check if we have a "IN" or "NOT IN" filter search)
386
- const tmpSearchTerms = [];
387
- if (operator === 'IN') {
388
- // example:: (Stage eq "Expired" or Stage eq "Renewal")
389
- for (let j = 0, lnj = searchTerms.length; j < lnj; j++) {
390
- tmpSearchTerms.push(`${fieldName} eq ${searchTerms[j]}`);
391
- }
392
- searchBy = tmpSearchTerms.join(' or ');
393
- }
394
- else {
395
- // example:: (Stage ne "Expired" and Stage ne "Renewal")
396
- for (let k = 0, lnk = searchTerms.length; k < lnk; k++) {
397
- tmpSearchTerms.push(`${fieldName} ne ${searchTerms[k]}`);
398
- }
399
- searchBy = tmpSearchTerms.join(' and ');
400
- }
401
- if (!(typeof searchBy === 'string' && searchBy[0] === '(' && searchBy.slice(-1) === ')')) {
402
- searchBy = `(${searchBy})`;
403
- }
404
- }
405
- else if (operator === '*' ||
406
- operator === 'a*' ||
407
- operator === '*z' ||
408
- lastValueChar === '*' ||
409
- operator === common_1.OperatorType.startsWith ||
410
- operator === common_1.OperatorType.endsWith) {
411
- // first/last character is a '*' will be a startsWith or endsWith
412
- searchBy =
413
- operator === '*' || operator === '*z' || operator === common_1.OperatorType.endsWith
414
- ? `endswith(${fieldName}, ${searchValue})`
415
- : `startswith(${fieldName}, ${searchValue})`;
416
- }
417
- else if (operator === common_1.OperatorType.rangeExclusive || operator === common_1.OperatorType.rangeInclusive) {
418
- // example:: (Name >= 'Bob' and Name <= 'Jane')
419
- searchBy = this.filterBySearchTermRange((0, utils_1.getHtmlStringOutput)(fieldName), operator, searchTerms);
420
- }
421
- else if ((operator === '' || operator === common_1.OperatorType.contains || operator === common_1.OperatorType.notContains) &&
422
- (fieldType === common_1.FieldType.string || fieldType === common_1.FieldType.text || fieldType === common_1.FieldType.readonly)) {
423
- searchBy = odataVersion >= 4 ? `contains(${fieldName}, ${searchValue})` : `substringof(${searchValue}, ${fieldName})`;
424
- if (operator === common_1.OperatorType.notContains) {
425
- searchBy = `not ${searchBy}`;
426
- }
427
- }
428
- else {
429
- // any other field type (or undefined type)
430
- searchBy = `${fieldName} ${this.mapOdataOperator(operator)} ${searchValue}`;
431
- }
432
- // push to our temp array and also trim white spaces
433
- if (searchBy !== '') {
434
- searchByArray.push(searchBy.trim());
435
- this.saveColumnFilter((0, utils_1.getHtmlStringOutput)(fieldName || ''), fieldSearchValue, searchValue);
436
- }
437
- }
438
- }
439
- }
440
- // update the service options with filters for the buildQuery() to work later
441
- this._odataService.updateOptions({
442
- filter: searchByArray.length > 0 ? searchByArray.join(' and ') : '',
443
- skip: undefined,
444
- });
445
- }
446
- /**
447
- * Update the pagination component with it's new page number and size
448
- * @param newPage
449
- * @param pageSize
450
- */
451
- updatePagination(newPage, pageSize) {
452
- this._currentPagination = {
453
- pageNumber: newPage,
454
- pageSize,
455
- };
456
- // unless user specifically set "enablePagination" to False, we'll update pagination options in every other cases
457
- if (this._gridOptions &&
458
- (this._gridOptions.enablePagination || !this._gridOptions.hasOwnProperty('enablePagination') || this.options?.infiniteScroll)) {
459
- this._odataService.updateOptions({
460
- top: pageSize,
461
- skip: (newPage - 1) * pageSize,
462
- });
463
- }
464
- }
465
- /**
466
- * loop through all columns to inspect sorters & update backend service orderBy
467
- * @param columnFilters
468
- */
469
- updateSorters(sortColumns, presetSorters) {
470
- let currentSorters = [];
471
- const odataSorters = [];
472
- if (!sortColumns && presetSorters) {
473
- // make the presets the current sorters, also make sure that all direction are in lowercase for OData
474
- currentSorters = presetSorters;
475
- currentSorters.forEach((sorter) => (sorter.direction = sorter.direction.toLowerCase()));
476
- // display the correct sorting icons on the UI, for that it requires (columnId, sortAsc) properties
477
- const tmpSorterArray = currentSorters.map((sorter) => {
478
- const columnDef = this._columnDefinitions.find((column) => column.id === sorter.columnId);
479
- odataSorters.push({
480
- field: columnDef ? (columnDef.queryFieldSorter || columnDef.queryField || columnDef.field) + '' : sorter.columnId + '',
481
- direction: sorter.direction,
482
- });
483
- // return only the column(s) found in the Column Definitions ELSE null
484
- if (columnDef) {
485
- return {
486
- columnId: sorter.columnId,
487
- sortAsc: sorter.direction.toUpperCase() === common_1.SortDirection.ASC,
488
- };
489
- }
490
- return null;
491
- });
492
- // set the sort icons, but also make sure to filter out null values (that happens when columnDef is not found)
493
- if (Array.isArray(tmpSorterArray) && this._grid) {
494
- this._grid.setSortColumns(tmpSorterArray);
495
- }
496
- }
497
- else if (sortColumns && !presetSorters) {
498
- // build the SortBy string, it could be multisort, example: customerNo asc, purchaserName desc
499
- if (sortColumns?.length === 0) {
500
- // TODO fix this line
501
- // currentSorters = new Array(this.defaultOptions.orderBy); // when empty, use the default sort
502
- }
503
- else {
504
- if (sortColumns) {
505
- for (const columnDef of sortColumns) {
506
- if (columnDef.sortCol) {
507
- let fieldName = (columnDef.sortCol.queryFieldSorter || columnDef.sortCol.queryField || columnDef.sortCol.field) + '';
508
- let columnFieldName = (columnDef.sortCol.field || columnDef.sortCol.id) + '';
509
- let queryField = (columnDef.sortCol.queryFieldSorter || columnDef.sortCol.queryField || columnDef.sortCol.field || '') + '';
510
- if (this._odataService.options.caseType === common_1.CaseType.pascalCase) {
511
- fieldName = (0, utils_1.titleCase)(fieldName);
512
- columnFieldName = (0, utils_1.titleCase)(columnFieldName);
513
- queryField = (0, utils_1.titleCase)(queryField);
514
- }
515
- currentSorters.push({
516
- columnId: columnDef.sortCol.id,
517
- direction: columnDef.sortAsc ? common_1.SortDirection.asc : common_1.SortDirection.desc,
518
- });
519
- if (queryField !== '') {
520
- odataSorters.push({
521
- field: queryField,
522
- direction: columnDef.sortAsc ? common_1.SortDirection.ASC : common_1.SortDirection.DESC,
523
- });
524
- }
525
- }
526
- }
527
- }
528
- }
529
- }
530
- // transform the sortby array into a CSV string for OData
531
- currentSorters = currentSorters || [];
532
- const csvString = odataSorters
533
- .map((sorter) => {
534
- let str = '';
535
- if (sorter && sorter.field) {
536
- const sortField = this._odataService.options.caseType === common_1.CaseType.pascalCase ? (0, utils_1.titleCase)(sorter.field) : sorter.field;
537
- str = `${sortField} ${(sorter && sorter.direction && sorter.direction.toLowerCase()) || ''}`;
538
- }
539
- return str;
540
- })
541
- .join(',');
542
- this._odataService.updateOptions({
543
- orderBy: csvString,
544
- });
545
- // keep current Sorters and update the service options with the new sorting
546
- this._currentSorters = currentSorters;
547
- // build the OData query which we will use in the WebAPI callback
548
- return this._odataService.buildQuery();
549
- }
550
- //
551
- // protected functions
552
- // -------------------
553
- /**
554
- * Cast provided filters (could be in multiple format) into an array of ColumnFilter
555
- * @param columnFilters
556
- */
557
- castFilterToColumnFilters(columnFilters) {
558
- // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
559
- const filtersArray = typeof columnFilters === 'object' ? Object.keys(columnFilters).map((key) => columnFilters[key]) : columnFilters;
560
- if (!Array.isArray(filtersArray)) {
561
- return [];
562
- }
563
- return filtersArray.map((filter) => {
564
- const tmpFilter = { columnId: filter.columnId || '' };
565
- if (filter.operator) {
566
- tmpFilter.operator = filter.operator;
567
- }
568
- if (filter.targetSelector) {
569
- tmpFilter.targetSelector = filter.targetSelector;
570
- }
571
- if (Array.isArray(filter.searchTerms)) {
572
- tmpFilter.searchTerms = filter.searchTerms;
573
- }
574
- return tmpFilter;
575
- });
576
- }
577
- /**
578
- * Filter by a range of searchTerms (2 searchTerms OR 1 string separated by 2 dots "value1..value2")
579
- */
580
- filterBySearchTermRange(fieldName, operator, searchTerms) {
581
- let query = '';
582
- if (Array.isArray(searchTerms) && searchTerms.length === 2) {
583
- if (operator === common_1.OperatorType.rangeInclusive) {
584
- // example:: (Duration >= 5 and Duration <= 10)
585
- query = `(${fieldName} ge ${searchTerms[0]}`;
586
- if (searchTerms[1] !== '') {
587
- query += ` and ${fieldName} le ${searchTerms[1]}`;
588
- }
589
- query += ')';
590
- }
591
- else if (operator === common_1.OperatorType.rangeExclusive) {
592
- // example:: (Duration > 5 and Duration < 10)
593
- query = `(${fieldName} gt ${searchTerms[0]}`;
594
- if (searchTerms[1] !== '') {
595
- query += ` and ${fieldName} lt ${searchTerms[1]}`;
596
- }
597
- query += ')';
598
- }
599
- }
600
- return query;
601
- }
602
- /**
603
- * Normalizes the search value according to field type and oData version.
604
- */
605
- normalizeSearchValue(fieldType, searchValue, version) {
606
- switch (fieldType) {
607
- case common_1.FieldType.date:
608
- searchValue = (0, common_1.parseUtcDate)(searchValue);
609
- searchValue = version >= 4 ? searchValue : `DateTime'${searchValue}'`;
610
- break;
611
- case common_1.FieldType.string:
612
- case common_1.FieldType.text:
613
- case common_1.FieldType.readonly:
614
- if (typeof searchValue === 'string') {
615
- // escape single quotes by doubling them
616
- searchValue = searchValue.replace(/'/g, `''`);
617
- // encode URI of the final search value
618
- searchValue = encodeURIComponent(searchValue);
619
- // strings need to be quoted.
620
- searchValue = `'${searchValue}'`;
621
- }
622
- break;
623
- case common_1.FieldType.integer:
624
- case common_1.FieldType.number:
625
- case common_1.FieldType.float:
626
- if (typeof searchValue === 'string') {
627
- // Parse a valid decimal from the string.
628
- // Replace double dots with single dots
629
- searchValue = searchValue.replace(/\.\./g, '.');
630
- // Remove a trailing dot
631
- searchValue = searchValue.replace(/\.+$/g, '');
632
- // Prefix a leading dot with 0
633
- searchValue = searchValue.replace(/^\.+/g, '0.');
634
- // Prefix leading dash dot with -0.
635
- searchValue = searchValue.replace(/^-+\.+/g, '-0.');
636
- // Remove any non valid decimal characters from the search string
637
- searchValue = searchValue.replace(/(?!^-)[^\d.]/g, '');
638
- // if nothing left, search for 0
639
- if (searchValue === '' || searchValue === '-') {
640
- searchValue = '0';
641
- }
642
- }
643
- break;
644
- }
645
- return searchValue;
646
- }
647
- }
648
- exports.GridOdataService = GridOdataService;
649
- //# sourceMappingURL=grid-odata.service.js.map