angular-odata 0.130.0 → 0.131.0

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 (159) hide show
  1. package/fesm2022/angular-odata.mjs +2298 -2162
  2. package/fesm2022/angular-odata.mjs.map +1 -1
  3. package/lib/api.d.ts +10 -11
  4. package/lib/cache/cache.d.ts +2 -2
  5. package/lib/cache/memory.d.ts +2 -2
  6. package/lib/cache/storage.d.ts +2 -2
  7. package/lib/loaders.d.ts +8 -8
  8. package/lib/metadata/csdl/csdl-annotation.d.ts +3 -3
  9. package/lib/metadata/csdl/csdl-entity-container.d.ts +2 -2
  10. package/lib/metadata/csdl/csdl-entity-set.d.ts +2 -2
  11. package/lib/metadata/csdl/csdl-enum-type.d.ts +3 -3
  12. package/lib/metadata/csdl/csdl-function-action.d.ts +4 -4
  13. package/lib/metadata/csdl/csdl-reference.d.ts +2 -2
  14. package/lib/metadata/csdl/csdl-schema.d.ts +2 -2
  15. package/lib/metadata/csdl/csdl-structural-property.d.ts +3 -3
  16. package/lib/metadata/csdl/csdl-structured-type.d.ts +3 -3
  17. package/lib/metadata/metadata.d.ts +2 -2
  18. package/lib/models/options.d.ts +2 -2
  19. package/lib/module.d.ts +3 -3
  20. package/lib/options.d.ts +3 -3
  21. package/lib/resources/query/expressions/apply.d.ts +1 -1
  22. package/lib/resources/query/expressions/compute.d.ts +1 -1
  23. package/lib/resources/query/expressions/count.d.ts +1 -1
  24. package/lib/resources/query/expressions/expand.d.ts +4 -3
  25. package/lib/resources/query/expressions/filter.d.ts +2 -1
  26. package/lib/resources/query/expressions/orderby.d.ts +2 -1
  27. package/lib/resources/query/expressions/search.d.ts +2 -1
  28. package/lib/resources/query/expressions/select.d.ts +2 -1
  29. package/lib/resources/query/handlers.d.ts +17 -5
  30. package/lib/resources/resource.d.ts +5 -5
  31. package/lib/resources/types/action.d.ts +2 -2
  32. package/lib/resources/types/entity-set.d.ts +2 -2
  33. package/lib/resources/types/navigation-property.d.ts +2 -2
  34. package/lib/resources/types/property.d.ts +2 -2
  35. package/lib/schema/annotation.d.ts +3 -3
  36. package/lib/schema/callable.d.ts +3 -3
  37. package/lib/schema/element.d.ts +3 -3
  38. package/lib/schema/entity-container.d.ts +2 -2
  39. package/lib/schema/entity-set.d.ts +2 -2
  40. package/lib/schema/enum-type.d.ts +2 -2
  41. package/lib/schema/parsers/callable.d.ts +4 -4
  42. package/lib/schema/parsers/enum-type.d.ts +3 -3
  43. package/lib/schema/parsers/structured-type.d.ts +4 -4
  44. package/lib/schema/schema.d.ts +3 -3
  45. package/lib/schema/singleton.d.ts +2 -2
  46. package/lib/schema/structured-type.d.ts +3 -3
  47. package/lib/services/entity.d.ts +1 -1
  48. package/lib/settings.d.ts +2 -2
  49. package/lib/types.d.ts +76 -74
  50. package/lib/utils/odata.d.ts +2 -2
  51. package/package.json +3 -5
  52. package/schematics/apigen/files/api-config/__fileName__.ts +4 -4
  53. package/esm2022/angular-odata.mjs +0 -5
  54. package/esm2022/lib/annotations.mjs +0 -146
  55. package/esm2022/lib/api.mjs +0 -439
  56. package/esm2022/lib/cache/cache.mjs +0 -177
  57. package/esm2022/lib/cache/index.mjs +0 -4
  58. package/esm2022/lib/cache/memory.mjs +0 -30
  59. package/esm2022/lib/cache/storage.mjs +0 -57
  60. package/esm2022/lib/client.mjs +0 -215
  61. package/esm2022/lib/constants.mjs +0 -95
  62. package/esm2022/lib/helper.mjs +0 -288
  63. package/esm2022/lib/index.mjs +0 -22
  64. package/esm2022/lib/loaders.mjs +0 -43
  65. package/esm2022/lib/metadata/csdl/csdl-annotation.mjs +0 -273
  66. package/esm2022/lib/metadata/csdl/csdl-entity-container.mjs +0 -59
  67. package/esm2022/lib/metadata/csdl/csdl-entity-set.mjs +0 -50
  68. package/esm2022/lib/metadata/csdl/csdl-enum-type.mjs +0 -74
  69. package/esm2022/lib/metadata/csdl/csdl-function-action.mjs +0 -204
  70. package/esm2022/lib/metadata/csdl/csdl-navigation-property-binding.mjs +0 -15
  71. package/esm2022/lib/metadata/csdl/csdl-reference.mjs +0 -76
  72. package/esm2022/lib/metadata/csdl/csdl-schema.mjs +0 -87
  73. package/esm2022/lib/metadata/csdl/csdl-singleton.mjs +0 -37
  74. package/esm2022/lib/metadata/csdl/csdl-structural-property.mjs +0 -145
  75. package/esm2022/lib/metadata/csdl/csdl-structured-type.mjs +0 -159
  76. package/esm2022/lib/metadata/csdl/csdl-type-definition.mjs +0 -46
  77. package/esm2022/lib/metadata/index.mjs +0 -3
  78. package/esm2022/lib/metadata/metadata.mjs +0 -41
  79. package/esm2022/lib/metadata/parser.mjs +0 -564
  80. package/esm2022/lib/models/collection.mjs +0 -816
  81. package/esm2022/lib/models/index.mjs +0 -4
  82. package/esm2022/lib/models/model.mjs +0 -577
  83. package/esm2022/lib/models/options.mjs +0 -1227
  84. package/esm2022/lib/module.mjs +0 -55
  85. package/esm2022/lib/options.mjs +0 -91
  86. package/esm2022/lib/resources/index.mjs +0 -7
  87. package/esm2022/lib/resources/options.mjs +0 -66
  88. package/esm2022/lib/resources/path/handlers.mjs +0 -81
  89. package/esm2022/lib/resources/path/index.mjs +0 -3
  90. package/esm2022/lib/resources/path/segments.mjs +0 -149
  91. package/esm2022/lib/resources/query/builder.mjs +0 -645
  92. package/esm2022/lib/resources/query/expressions/apply.mjs +0 -238
  93. package/esm2022/lib/resources/query/expressions/base.mjs +0 -26
  94. package/esm2022/lib/resources/query/expressions/compute.mjs +0 -55
  95. package/esm2022/lib/resources/query/expressions/count.mjs +0 -118
  96. package/esm2022/lib/resources/query/expressions/expand.mjs +0 -154
  97. package/esm2022/lib/resources/query/expressions/filter.mjs +0 -180
  98. package/esm2022/lib/resources/query/expressions/index.mjs +0 -10
  99. package/esm2022/lib/resources/query/expressions/orderby.mjs +0 -81
  100. package/esm2022/lib/resources/query/expressions/search.mjs +0 -144
  101. package/esm2022/lib/resources/query/expressions/select.mjs +0 -49
  102. package/esm2022/lib/resources/query/expressions/syntax.mjs +0 -770
  103. package/esm2022/lib/resources/query/handlers.mjs +0 -423
  104. package/esm2022/lib/resources/query/index.mjs +0 -5
  105. package/esm2022/lib/resources/query/options.mjs +0 -140
  106. package/esm2022/lib/resources/request.mjs +0 -210
  107. package/esm2022/lib/resources/resource.mjs +0 -316
  108. package/esm2022/lib/resources/response.mjs +0 -180
  109. package/esm2022/lib/resources/types/action.mjs +0 -118
  110. package/esm2022/lib/resources/types/batch.mjs +0 -428
  111. package/esm2022/lib/resources/types/count.mjs +0 -33
  112. package/esm2022/lib/resources/types/entity-set.mjs +0 -131
  113. package/esm2022/lib/resources/types/entity.mjs +0 -112
  114. package/esm2022/lib/resources/types/function.mjs +0 -149
  115. package/esm2022/lib/resources/types/index.mjs +0 -15
  116. package/esm2022/lib/resources/types/media.mjs +0 -44
  117. package/esm2022/lib/resources/types/metadata.mjs +0 -35
  118. package/esm2022/lib/resources/types/navigation-property.mjs +0 -246
  119. package/esm2022/lib/resources/types/options.mjs +0 -2
  120. package/esm2022/lib/resources/types/property.mjs +0 -187
  121. package/esm2022/lib/resources/types/reference.mjs +0 -87
  122. package/esm2022/lib/resources/types/singleton.mjs +0 -125
  123. package/esm2022/lib/resources/types/value.mjs +0 -48
  124. package/esm2022/lib/schema/annotation.mjs +0 -44
  125. package/esm2022/lib/schema/callable.mjs +0 -69
  126. package/esm2022/lib/schema/element.mjs +0 -70
  127. package/esm2022/lib/schema/entity-container.mjs +0 -13
  128. package/esm2022/lib/schema/entity-set.mjs +0 -11
  129. package/esm2022/lib/schema/enum-type.mjs +0 -69
  130. package/esm2022/lib/schema/index.mjs +0 -9
  131. package/esm2022/lib/schema/parsers/callable.mjs +0 -123
  132. package/esm2022/lib/schema/parsers/edm.mjs +0 -101
  133. package/esm2022/lib/schema/parsers/enum-type.mjs +0 -148
  134. package/esm2022/lib/schema/parsers/index.mjs +0 -5
  135. package/esm2022/lib/schema/parsers/structured-type.mjs +0 -548
  136. package/esm2022/lib/schema/schema.mjs +0 -52
  137. package/esm2022/lib/schema/singleton.mjs +0 -11
  138. package/esm2022/lib/schema/structured-type.mjs +0 -220
  139. package/esm2022/lib/services/base.mjs +0 -32
  140. package/esm2022/lib/services/entity-set.mjs +0 -161
  141. package/esm2022/lib/services/entity.mjs +0 -12
  142. package/esm2022/lib/services/factory.mjs +0 -39
  143. package/esm2022/lib/services/index.mjs +0 -5
  144. package/esm2022/lib/services/singleton.mjs +0 -55
  145. package/esm2022/lib/settings.mjs +0 -113
  146. package/esm2022/lib/types.mjs +0 -118
  147. package/esm2022/lib/utils/arraybuffers.mjs +0 -46
  148. package/esm2022/lib/utils/arrays.mjs +0 -10
  149. package/esm2022/lib/utils/dates.mjs +0 -18
  150. package/esm2022/lib/utils/durations.mjs +0 -40
  151. package/esm2022/lib/utils/enums.mjs +0 -61
  152. package/esm2022/lib/utils/http.mjs +0 -95
  153. package/esm2022/lib/utils/index.mjs +0 -10
  154. package/esm2022/lib/utils/objects.mjs +0 -204
  155. package/esm2022/lib/utils/odata.mjs +0 -22
  156. package/esm2022/lib/utils/strings.mjs +0 -20
  157. package/esm2022/lib/utils/types.mjs +0 -136
  158. package/esm2022/lib/utils/urls.mjs +0 -24
  159. package/esm2022/public-api.mjs +0 -5
@@ -1,7 +1,7 @@
1
1
  import * as i1 from '@angular/common/http';
2
2
  import { HttpHeaders, HttpParams, HttpResponse, HttpErrorResponse, HttpEventType, HttpClientModule } from '@angular/common/http';
3
- import { of, throwError, Subject, map as map$1, EMPTY, Observable, forkJoin, NEVER } from 'rxjs';
4
- import { tap, startWith, map, expand, reduce, finalize, defaultIfEmpty, switchMap, catchError } from 'rxjs/operators';
3
+ import { Subject, map as map$1, EMPTY, throwError, Observable, forkJoin, of, NEVER } from 'rxjs';
4
+ import { map, expand, reduce, finalize, defaultIfEmpty, switchMap, catchError, tap, startWith } from 'rxjs/operators';
5
5
  import * as i0 from '@angular/core';
6
6
  import { EventEmitter, Injectable, InjectionToken, makeEnvironmentProviders, NgModule } from '@angular/core';
7
7
  import { CommonModule } from '@angular/common';
@@ -219,2177 +219,1975 @@ const DESCRIPTION = /.*Description$/;
219
219
  const LONG_DESCRIPTION = /.*LongDescription$/;
220
220
  const OPTIONARL_PARAMETER = /.*OptionalParameter$/;
221
221
 
222
- class ODataCache {
223
- timeout;
224
- entries;
225
- constructor({ timeout = DEFAULT_TIMEOUT }) {
226
- this.timeout = timeout;
227
- this.entries = new Map();
228
- }
229
- /**
230
- * Using the resource on the request build an array of string to identify the scope of the request
231
- * @param req The request with the resource to build the scope
232
- * @returns Array of string to identify the scope of the request
233
- */
234
- scope(req) {
235
- const segments = req.resource.cloneSegments();
236
- return segments.segments({ key: true }).reduce((acc, s) => {
237
- if (s.name === PathSegment.entitySet)
238
- acc = [...acc, s.path()];
239
- return acc;
240
- }, ['request']);
241
- }
242
- /**
243
- * Using the odata context on the response build an array of string to identify the tags of the response
244
- * @param res The response to build the tags
245
- * @returns Array of string to identify the tags of the response
246
- */
247
- tags(res) {
248
- const tags = [];
249
- const context = res.context;
250
- if (context.entitySet) {
251
- tags.push(context.key
252
- ? `${context.entitySet}(${context.key})`
253
- : context.entitySet);
254
- }
255
- if (context.type)
256
- tags.push(context.type);
257
- return tags;
258
- }
259
- /**
260
- * Build an entry from a payload and some options
261
- * @param payload The payload to store in the cache
262
- * @param timeout The timeout for the entry
263
- * @param tags The tags for the entry
264
- * @returns The entry to store in the cache
265
- */
266
- buildEntry(payload, { timeout, tags }) {
267
- return {
268
- payload,
269
- lastRead: Date.now(),
270
- timeout: timeout || this.timeout,
271
- tags: tags || [],
272
- };
273
- }
274
- /**
275
- * Build a key from store an entry in the cache
276
- * @param names The names of the entry
277
- * @returns The key for the entry
278
- */
279
- buildKey(names) {
280
- return names.join(CACHE_KEY_SEPARATOR);
281
- }
282
- /**
283
- * Put some payload in the cache
284
- * @param name The name for the entry
285
- * @param payload The payload to store in the cache
286
- * @param timeout The timeout for the entry
287
- * @param scope The scope for the entry
288
- * @param tags The tags for the entry
289
- */
290
- put(name, payload, { timeout, scope, tags, } = {}) {
291
- const entry = this.buildEntry(payload, { timeout, tags });
292
- const key = this.buildKey([...(scope || []), name]);
293
- this.entries.set(key, entry);
294
- this.forget();
295
- }
296
- /**
297
- * Return the payload from the cache if it exists and is not expired
298
- * @param name The name of the entry
299
- * @param scope The scope of the entry
300
- * @returns The payload of the entry
301
- */
302
- get(name, { scope } = {}) {
303
- const key = this.buildKey([...(scope || []), name]);
304
- const entry = this.entries.get(key);
305
- return entry !== undefined && !this.isExpired(entry)
306
- ? entry.payload
307
- : undefined;
308
- }
309
- /**
310
- * Remove all cache entries that are matching with the given options
311
- * @param options The options to forget
312
- */
313
- forget({ name, scope = [], tags = [], } = {}) {
314
- if (name !== undefined)
315
- scope.push(name);
316
- const key = scope.length > 0 ? this.buildKey(scope) : undefined;
317
- this.entries.forEach((entry, k) => {
318
- if (this.isExpired(entry) || // Expired
319
- (key !== undefined && k.startsWith(key)) || // Key
320
- (tags.length > 0 && tags.some((t) => entry.tags.indexOf(t) !== -1)) // Tags
321
- ) {
322
- this.entries.delete(k);
323
- }
324
- });
325
- }
326
- /**
327
- * Remove all cache entries
328
- */
329
- flush() {
330
- this.entries = new Map();
331
- }
332
- /**
333
- * Check if the entry is expired
334
- * @param entry The cache entry
335
- * @returns Boolean indicating if the entry is expired
336
- */
337
- isExpired(entry) {
338
- return entry.lastRead < Date.now() - (entry.timeout || this.timeout) * 1000;
339
- }
340
- /**
341
- * Using the request, handle the fetching of the response
342
- * @param req The request to fetch
343
- * @param res$ Observable of the response
344
- * @returns
345
- */
346
- handleRequest(req, res$) {
347
- return req.isFetch()
348
- ? this.handleFetch(req, res$)
349
- : req.isMutate()
350
- ? this.handleMutate(req, res$)
351
- : res$;
352
- }
353
- handleFetch(req, res$) {
354
- const policy = req.fetchPolicy;
355
- const cached = this.getResponse(req);
356
- if (policy === 'no-cache') {
357
- return res$;
358
- }
359
- if (policy === 'cache-only') {
360
- if (cached) {
361
- return of(cached);
362
- }
363
- else {
364
- return throwError(() => new Error('No Cached'));
365
- }
366
- }
367
- if (policy === 'cache-first' ||
368
- policy === 'cache-and-network' ||
369
- policy === 'network-only') {
370
- res$ = res$.pipe(tap((res) => {
371
- if (res.options.cacheability !== 'no-store')
372
- this.putResponse(req, res);
373
- }));
374
- }
375
- return cached !== undefined && policy !== 'network-only'
376
- ? policy === 'cache-and-network'
377
- ? res$.pipe(startWith(cached))
378
- : of(cached)
379
- : res$;
380
- }
381
- handleMutate(req, res$) {
382
- const requests = req.isBatch()
383
- ? req.resource
384
- .requests()
385
- .filter((r) => r.isMutate())
386
- : [req];
387
- for (var r of requests) {
388
- const scope = this.scope(r);
389
- this.forget({ scope });
390
- }
391
- return res$;
392
- }
393
- }
394
-
395
- class ODataInMemoryCache extends ODataCache {
396
- constructor({ timeout } = {}) {
397
- super({ timeout });
398
- }
399
- /**
400
- * Store the response in the cache
401
- * @param req The request with the resource to store the response
402
- * @param res The response to store in the cache
403
- */
404
- putResponse(req, res) {
405
- let scope = this.scope(req);
406
- let tags = this.tags(res);
407
- this.put(req.cacheKey, res, {
408
- timeout: res.options.maxAge,
409
- scope,
410
- tags,
411
- });
412
- }
413
- /**
414
- * Restore the response from the cache
415
- * @param req The request with the resource to get the response
416
- * @returns The response from the cache
417
- */
418
- getResponse(req) {
419
- let scope = this.scope(req);
420
- return this.get(req.cacheKey, { scope });
421
- }
422
- }
423
-
424
- const COMPARISON_OPERATORS = ['eq', 'ne', 'gt', 'ge', 'lt', 'le'];
425
- const LOGICAL_OPERATORS = ['and', 'or', 'not'];
426
- const COLLECTION_OPERATORS = ['any', 'all'];
427
- const BOOLEAN_FUNCTIONS = ['startswith', 'endswith', 'contains'];
428
- const SUPPORTED_EXPAND_PROPERTIES = [
429
- 'expand',
430
- 'levels',
431
- 'select',
432
- 'top',
433
- 'count',
434
- 'orderby',
435
- 'filter',
436
- ];
437
- const FUNCTION_REGEX = /\((.*)\)/;
438
- const INDEXOF_REGEX = /(?!indexof)\((\w+)\)/;
439
- var StandardAggregateMethods;
440
- (function (StandardAggregateMethods) {
441
- StandardAggregateMethods["sum"] = "sum";
442
- StandardAggregateMethods["min"] = "min";
443
- StandardAggregateMethods["max"] = "max";
444
- StandardAggregateMethods["average"] = "average";
445
- StandardAggregateMethods["countdistinct"] = "countdistinct";
446
- })(StandardAggregateMethods || (StandardAggregateMethods = {}));
447
- var QueryCustomTypes;
448
- (function (QueryCustomTypes) {
449
- QueryCustomTypes[QueryCustomTypes["Raw"] = 0] = "Raw";
450
- QueryCustomTypes[QueryCustomTypes["Alias"] = 1] = "Alias";
451
- QueryCustomTypes[QueryCustomTypes["Duration"] = 2] = "Duration";
452
- QueryCustomTypes[QueryCustomTypes["Binary"] = 3] = "Binary";
453
- })(QueryCustomTypes || (QueryCustomTypes = {}));
454
- //https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_QueryOptions
455
- const raw = (value) => ({
456
- type: QueryCustomTypes.Raw,
457
- value,
458
- });
459
- const alias = (value, name) => ({
460
- type: QueryCustomTypes.Alias,
461
- value,
462
- name,
463
- });
464
- const duration = (value) => ({
465
- type: QueryCustomTypes.Duration,
466
- value,
467
- });
468
- const binary = (value) => ({
469
- type: QueryCustomTypes.Binary,
470
- value,
471
- });
472
- const isQueryCustomType = (value) => typeof value === 'object' &&
473
- 'type' in value &&
474
- value.type in QueryCustomTypes;
475
- const isRawType = (value) => isQueryCustomType(value) &&
476
- value.type === QueryCustomTypes.Raw;
477
- const ITEM_ROOT = '';
478
- function builder ({ select, search, skiptoken, format, top, skip, filter, transform, compute, orderBy, key, count, expand, action, func, aliases, escape, } = {}) {
479
- const [path, params] = buildPathAndQuery({
480
- select,
481
- search,
482
- skiptoken,
483
- format,
484
- top,
485
- skip,
486
- filter,
487
- transform,
488
- compute,
489
- orderBy,
490
- key,
491
- count,
492
- expand,
493
- action,
494
- func,
495
- aliases,
496
- escape,
497
- });
498
- return buildUrl(path, params);
499
- }
500
- function buildPathAndQuery({ select, search, skiptoken, format, top, skip, filter, apply, transform, compute, orderBy, key, count, expand, action, func, aliases, escape, } = {}) {
501
- let path = '';
502
- aliases = aliases || [];
503
- const query = {};
504
- // key is not (null, undefined)
505
- if (key != undefined) {
506
- path += `(${normalizeValue(key, { aliases, escape })})`;
507
- }
508
- // Select
509
- if (select) {
510
- query.$select = isRawType(select)
511
- ? select.value
512
- : Array.isArray(select)
513
- ? select.join(',')
514
- : select;
515
- }
516
- // Compute
517
- if (compute) {
518
- query.$compute = isRawType(compute)
519
- ? compute.value
520
- : Array.isArray(compute)
521
- ? compute.join(',')
522
- : compute;
523
- }
524
- // Search
525
- if (search) {
526
- query.$search = search;
527
- }
528
- // Skiptoken
529
- if (skiptoken) {
530
- query.$skiptoken = skiptoken;
531
- }
532
- // Format
533
- if (format) {
534
- query.$format = format;
535
- }
536
- // Filter
537
- if (filter || typeof count === 'object') {
538
- query.$filter = buildFilter(typeof count === 'object' ? count : filter, {
539
- aliases,
540
- escape,
541
- });
542
- }
543
- // Transform
544
- if (transform) {
545
- query.$apply = buildTransforms(transform, { aliases, escape });
546
- }
547
- // Apply
548
- if (apply) {
549
- query.$apply = query.$apply
550
- ? query.$apply + '/' + buildApply(apply, { aliases, escape })
551
- : buildApply(apply, { aliases, escape });
552
- }
553
- // Expand
554
- if (expand) {
555
- query.$expand = buildExpand(expand, { aliases, escape });
556
- }
557
- // OrderBy
558
- if (orderBy) {
559
- query.$orderby = buildOrderBy(orderBy);
560
- }
561
- // Count
562
- if (isRawType(count)) {
563
- query.$count = count.value;
564
- }
565
- else if (typeof count === 'boolean') {
566
- query.$count = true;
567
- }
568
- else if (count) {
569
- path += '/$count';
570
- }
571
- // Top
572
- if (isRawType(top)) {
573
- query.$top = top.value;
574
- }
575
- else if (typeof top === 'number') {
576
- query.$top = top;
577
- }
578
- // Skip
579
- if (isRawType(skip)) {
580
- query.$top = skip.value;
581
- }
582
- else if (typeof skip === 'number') {
583
- query.$skip = skip;
584
- }
585
- if (action) {
586
- path += `/${action}`;
587
- }
588
- if (func) {
589
- if (typeof func === 'string') {
590
- path += `/${func}()`;
591
- }
592
- else if (typeof func === 'object') {
593
- const [funcName] = Object.keys(func);
594
- const funcArgs = normalizeValue(func[funcName], {
595
- aliases,
596
- escape,
597
- });
598
- path += `/${funcName}(${funcArgs})`;
599
- }
600
- }
601
- if (aliases.length > 0) {
602
- Object.assign(query, aliases.reduce((acc, alias) => Object.assign(acc, {
603
- [`@${alias.name}`]: normalizeValue(alias.value, {
604
- escape,
605
- }),
606
- }), {}));
607
- }
608
- // Filter empty values
609
- const params = Object.entries(query)
610
- .filter(([, value]) => value !== undefined && value !== '')
611
- .reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), {});
612
- return [path, params];
613
- }
614
- function renderPrimitiveValue(key, val, { aliases, escape, }) {
615
- return `${key} eq ${normalizeValue(val, { aliases, escape })}`;
616
- }
617
- function buildFilter(filters = {}, { aliases, propPrefix, escape, }) {
618
- return (Array.isArray(filters) ? filters : [filters]).reduce((acc, filter) => {
619
- if (filter) {
620
- const builtFilter = buildFilterCore(filter, {
621
- aliases,
622
- propPrefix,
623
- escape,
624
- });
625
- if (builtFilter) {
626
- acc.push(builtFilter);
627
- }
628
- }
629
- return acc;
630
- }, []).join(' and ');
631
- function buildFilterCore(filter = {}, { aliases, propPrefix, escape, }) {
632
- let filterExpr = '';
633
- if (isRawType(filter)) {
634
- // Use raw query custom filter string
635
- filterExpr = filter.value;
636
- }
637
- else if (typeof filter === 'string') {
638
- // Use raw filter string
639
- filterExpr = filter;
640
- }
641
- else if (filter && typeof filter === 'object') {
642
- const filtersArray = Object.keys(filter).reduce((result, filterKey) => {
643
- const value = filter[filterKey];
644
- let propName = '';
645
- if (propPrefix) {
646
- if (filterKey === ITEM_ROOT) {
647
- propName = propPrefix;
648
- }
649
- else if (INDEXOF_REGEX.test(filterKey)) {
650
- propName = filterKey.replace(INDEXOF_REGEX, (_, $1) => $1.trim() === ITEM_ROOT
651
- ? `(${propPrefix})`
652
- : `(${propPrefix}/${$1.trim()})`);
653
- }
654
- else if (FUNCTION_REGEX.test(filterKey)) {
655
- propName = filterKey.replace(FUNCTION_REGEX, (_, $1) => $1.trim() === ITEM_ROOT
656
- ? `(${propPrefix})`
657
- : `(${propPrefix}/${$1.trim()})`);
658
- }
659
- else {
660
- propName = `${propPrefix}/${filterKey}`;
661
- }
662
- }
663
- else {
664
- propName = filterKey;
665
- }
666
- if (filterKey === ITEM_ROOT && Array.isArray(value)) {
667
- return result.concat(value.map((arrayValue) => renderPrimitiveValue(propName, arrayValue, { escape, aliases })));
668
- }
669
- if (['number', 'string', 'boolean'].indexOf(typeof value) !== -1 ||
670
- value instanceof Date ||
671
- value === null) {
672
- // Simple key/value handled as equals operator
673
- result.push(renderPrimitiveValue(propName, value, { aliases, escape }));
674
- }
675
- else if (Array.isArray(value)) {
676
- const op = filterKey;
677
- const builtFilters = value
678
- .map((v) => buildFilter(v, { aliases, propPrefix, escape }))
679
- .filter((f) => f)
680
- .map((f) => LOGICAL_OPERATORS.indexOf(op) !== -1 ? `(${f})` : f);
681
- if (builtFilters.length) {
682
- if (LOGICAL_OPERATORS.indexOf(op) !== -1) {
683
- if (builtFilters.length) {
684
- if (op === 'not') {
685
- result.push(parseNot(builtFilters));
686
- }
687
- else {
688
- result.push(`(${builtFilters.join(` ${op} `)})`);
689
- }
690
- }
691
- }
692
- else {
693
- result.push(builtFilters.join(` ${op} `));
694
- }
695
- }
696
- }
697
- else if (LOGICAL_OPERATORS.indexOf(propName) !== -1) {
698
- const op = propName;
699
- const builtFilters = Object.keys(value).map((valueKey) => buildFilterCore({ [valueKey]: value[valueKey] }, { aliases, escape }));
700
- if (builtFilters.length) {
701
- if (op === 'not') {
702
- result.push(parseNot(builtFilters));
703
- }
704
- else {
705
- result.push(`${builtFilters.join(` ${op} `)}`);
706
- }
707
- }
708
- }
709
- else if (typeof value === 'object') {
710
- if ('type' in value) {
711
- result.push(renderPrimitiveValue(propName, value, { aliases, escape }));
712
- }
713
- else {
714
- const operators = Object.keys(value);
715
- operators.forEach((op) => {
716
- if (COMPARISON_OPERATORS.indexOf(op) !== -1) {
717
- result.push(`${propName} ${op} ${normalizeValue(value[op], {
718
- aliases,
719
- escape,
720
- })}`);
721
- }
722
- else if (LOGICAL_OPERATORS.indexOf(op) !== -1) {
723
- if (Array.isArray(value[op])) {
724
- result.push(value[op]
725
- .map((v) => '(' +
726
- buildFilterCore(v, {
727
- aliases,
728
- propPrefix: propName,
729
- escape,
730
- }) +
731
- ')')
732
- .join(` ${op} `));
733
- }
734
- else {
735
- result.push('(' +
736
- buildFilterCore(value[op], {
737
- aliases,
738
- propPrefix: propName,
739
- escape,
740
- }) +
741
- ')');
742
- }
743
- }
744
- else if (COLLECTION_OPERATORS.indexOf(op) !== -1) {
745
- const collectionClause = buildCollectionClause(filterKey.toLowerCase(), value[op], op, propName);
746
- if (collectionClause) {
747
- result.push(collectionClause);
748
- }
749
- }
750
- else if (op === 'has') {
751
- result.push(`${propName} ${op} ${normalizeValue(value[op], {
752
- aliases,
753
- escape,
754
- })}`);
755
- }
756
- else if (op === 'in') {
757
- const resultingValues = Array.isArray(value[op])
758
- ? value[op]
759
- : value[op].value.map((typedValue) => ({
760
- type: value[op].type,
761
- value: typedValue,
762
- }));
763
- result.push(propName +
764
- ' in (' +
765
- resultingValues
766
- .map((v) => normalizeValue(v, { aliases, escape }))
767
- .join(',') +
768
- ')');
769
- }
770
- else if (BOOLEAN_FUNCTIONS.indexOf(op) !== -1) {
771
- // Simple boolean functions (startswith, endswith, contains)
772
- result.push(`${op}(${propName},${normalizeValue(value[op], {
773
- aliases,
774
- escape,
775
- })})`);
776
- }
777
- else {
778
- // Nested property
779
- const filter = buildFilterCore(value, {
780
- aliases,
781
- propPrefix: propName,
782
- escape,
783
- });
784
- if (filter) {
785
- result.push(filter);
786
- }
787
- }
788
- });
789
- }
790
- }
791
- else if (value === undefined) {
792
- // Ignore/omit filter if value is `undefined`
793
- }
794
- else {
795
- throw new Error(`Unexpected value type: ${value}`);
796
- }
797
- return result;
798
- }, []);
799
- filterExpr = filtersArray.join(' and ');
800
- } /* else {
801
- throw new Error(`Unexpected filters type: ${filter}`);
802
- } */
803
- return filterExpr;
804
- }
805
- function buildCollectionClause(lambdaParameter, value, op, propName) {
806
- let clause = '';
807
- if (typeof value === 'string' || value instanceof String) {
808
- clause = getStringCollectionClause(lambdaParameter, value, op, propName);
809
- }
810
- else if (value) {
811
- // normalize {any:[{prop1: 1}, {prop2: 1}]} --> {any:{prop1: 1, prop2: 1}}; same for 'all',
812
- // simple values collection: {any:[{'': 'simpleVal1'}, {'': 'simpleVal2'}]} --> {any:{'': ['simpleVal1', 'simpleVal2']}}; same for 'all',
813
- const filterValue = Array.isArray(value)
814
- ? value.reduce((acc, item) => {
815
- if (item.hasOwnProperty(ITEM_ROOT)) {
816
- if (!acc.hasOwnProperty(ITEM_ROOT)) {
817
- acc[ITEM_ROOT] = [];
818
- }
819
- acc[ITEM_ROOT].push(item[ITEM_ROOT]);
820
- return acc;
821
- }
822
- return { ...acc, ...item };
823
- }, {})
824
- : value;
825
- const filter = buildFilterCore(filterValue, {
826
- aliases,
827
- propPrefix: lambdaParameter,
828
- escape,
829
- });
830
- clause = `${propName}/${op}(${filter ? `${lambdaParameter}:${filter}` : ''})`;
831
- }
832
- return clause;
833
- }
834
- }
835
- function getStringCollectionClause(lambdaParameter, value, collectionOperator, propName) {
836
- let clause = '';
837
- const conditionOperator = collectionOperator == 'all' ? 'ne' : 'eq';
838
- clause = `${propName}/${collectionOperator}(${lambdaParameter}: ${lambdaParameter} ${conditionOperator} '${value}')`;
839
- return clause;
840
- }
841
- function escapeIllegalChars(string) {
842
- string = string.replace(/%/g, '%25');
843
- string = string.replace(/\+/g, '%2B');
844
- string = string.replace(/\//g, '%2F');
845
- string = string.replace(/\?/g, '%3F');
846
- string = string.replace(/#/g, '%23');
847
- string = string.replace(/&/g, '%26');
848
- string = string.replace(/'/g, "''");
849
- return string;
850
- }
851
- function normalizeValue(value, { aliases, escape = false, } = {}) {
852
- if (typeof value === 'string') {
853
- return escape ? `'${escapeIllegalChars(value)}'` : `'${value}'`;
854
- }
855
- else if (value instanceof Date) {
856
- return value.toISOString();
857
- }
858
- else if (typeof value === 'number') {
859
- return value;
860
- }
861
- else if (Array.isArray(value)) {
862
- return `[${value
863
- .map((d) => normalizeValue(d, { aliases, escape }))
864
- .join(',')}]`;
865
- }
866
- else if (value === null) {
867
- return value;
868
- }
869
- else if (typeof value === 'object') {
870
- switch (value.type) {
871
- case QueryCustomTypes.Raw:
872
- return value.value;
873
- case QueryCustomTypes.Duration:
874
- return `duration'${value.value}'`;
875
- case QueryCustomTypes.Binary:
876
- return `binary'${value.value}'`;
877
- case QueryCustomTypes.Alias:
878
- // Store
879
- if (Array.isArray(aliases)) {
880
- if (value.name === undefined) {
881
- value.name = `a${aliases.length + 1}`;
882
- }
883
- aliases.push(value);
884
- }
885
- return `@${value.name}`;
886
- default:
887
- return Object.entries(value)
888
- .filter(([, v]) => v !== undefined)
889
- .map(([k, v]) => `${k}=${normalizeValue(v, { aliases, escape })}`)
890
- .join(',');
891
- }
892
- }
893
- return value;
894
- }
895
- function buildExpand(expands, { aliases, escape = false, }) {
896
- if (isRawType(expands)) {
897
- return expands.value;
898
- }
899
- else if (typeof expands === 'number') {
900
- return expands;
901
- }
902
- else if (typeof expands === 'string') {
903
- if (expands.indexOf('/') === -1) {
904
- return expands;
905
- }
906
- // Change `Foo/Bar/Baz` to `Foo($expand=Bar($expand=Baz))`
907
- return expands
908
- .split('/')
909
- .reverse()
910
- .reduce((results, item, index, arr) => {
911
- if (index === 0) {
912
- // Inner-most item
913
- return `$expand=${item}`;
914
- }
915
- else if (index === arr.length - 1) {
916
- // Outer-most item, don't add `$expand=` prefix (added above)
917
- return `${item}(${results})`;
918
- }
919
- else {
920
- // Other items
921
- return `$expand=${item}(${results})`;
922
- }
923
- }, '');
924
- }
925
- else if (Array.isArray(expands)) {
926
- return `${expands
927
- .map((e) => buildExpand(e, { aliases, escape }))
928
- .join(',')}`;
929
- }
930
- else if (typeof expands === 'object') {
931
- const expandKeys = Object.keys(expands);
932
- if (expandKeys.some((key) => SUPPORTED_EXPAND_PROPERTIES.indexOf(key.toLowerCase()) !== -1)) {
933
- return expandKeys
934
- .map((key) => {
935
- let value;
936
- switch (key) {
937
- case 'filter':
938
- value = buildFilter(expands[key], {
939
- aliases,
940
- escape,
941
- });
942
- break;
943
- case 'orderBy':
944
- value = buildOrderBy(expands[key]);
945
- break;
946
- case 'levels':
947
- case 'count':
948
- case 'top':
949
- case 'skip':
950
- value = `${expands[key]}`;
951
- if (isRawType(value))
952
- value = value.value;
953
- break;
954
- default:
955
- value = buildExpand(expands[key], { aliases, escape });
956
- }
957
- return `$${key.toLowerCase()}=${value}`;
958
- })
959
- .join(';');
960
- }
961
- else {
962
- return expandKeys
963
- .map((key) => {
964
- const builtExpand = buildExpand(expands[key], { aliases, escape });
965
- return builtExpand ? `${key}(${builtExpand})` : key;
966
- })
967
- .join(',');
968
- }
969
- }
970
- return '';
971
- }
972
- function buildTransforms(transforms, { aliases, escape = false, }) {
973
- // Wrap single object an array for simplified processing
974
- const transformsArray = Array.isArray(transforms) ? transforms : [transforms];
975
- const transformsResult = transformsArray.reduce((result, transform) => {
976
- const { aggregate, filter, groupBy, ...rest } = transform;
977
- // TODO: support as many of the following:
978
- // topcount, topsum, toppercent,
979
- // bottomsum, bottomcount, bottompercent,
980
- // identity, concat, expand, search, compute, isdefined
981
- const unsupportedKeys = Object.keys(rest);
982
- if (unsupportedKeys.length) {
983
- throw new Error(`Unsupported transform(s): ${unsupportedKeys}`);
984
- }
985
- if (aggregate) {
986
- result.push(`aggregate(${buildAggregate(aggregate)})`);
987
- }
988
- if (filter) {
989
- const builtFilter = buildFilter(filter, { aliases, escape });
990
- if (builtFilter) {
991
- result.push(`filter(${buildFilter(builtFilter, { aliases, escape })})`);
992
- }
993
- }
994
- if (groupBy) {
995
- result.push(`groupby(${buildGroupBy(groupBy, { aliases, escape })})`);
996
- }
997
- return result;
998
- }, []);
999
- return transformsResult.join('/') || undefined;
1000
- }
1001
- function buildAggregate(aggregate) {
1002
- // Wrap single object in an array for simplified processing
1003
- const aggregateArray = Array.isArray(aggregate) ? aggregate : [aggregate];
1004
- return aggregateArray
1005
- .map((aggregateItem) => {
1006
- return typeof aggregateItem === 'string'
1007
- ? aggregateItem
1008
- : Object.keys(aggregateItem).map((aggregateKey) => {
1009
- const aggregateValue = aggregateItem[aggregateKey];
1010
- // TODO: Are these always required? Can/should we default them if so?
1011
- if (!aggregateValue.with) {
1012
- throw new Error(`'with' property required for '${aggregateKey}'`);
1013
- }
1014
- if (!aggregateValue.as) {
1015
- throw new Error(`'as' property required for '${aggregateKey}'`);
1016
- }
1017
- return `${aggregateKey} with ${aggregateValue.with} as ${aggregateValue.as}`;
1018
- });
1019
- })
1020
- .join(',');
1021
- }
1022
- function buildGroupBy(groupBy, { aliases, escape = false, }) {
1023
- if (!groupBy.properties) {
1024
- throw new Error(`'properties' property required for groupBy`);
1025
- }
1026
- let result = `(${groupBy.properties.join(',')})`;
1027
- if (groupBy.transform) {
1028
- result += `,${buildTransforms(groupBy.transform, { aliases, escape })}`;
1029
- }
1030
- return result;
1031
- }
1032
- function buildOrderBy(orderBy, prefix = '') {
1033
- if (isRawType(orderBy)) {
1034
- return orderBy.value;
1035
- }
1036
- else if (Array.isArray(orderBy)) {
1037
- return orderBy
1038
- .map((value) => Array.isArray(value) &&
1039
- value.length === 2 &&
1040
- ['asc', 'desc'].indexOf(value[1]) !== -1
1041
- ? value.join(' ')
1042
- : value)
1043
- .map((v) => `${prefix}${v}`)
1044
- .join(',');
1045
- }
1046
- else if (typeof orderBy === 'object') {
1047
- return Object.entries(orderBy)
1048
- .map(([k, v]) => buildOrderBy(v, `${k}/`))
1049
- .map((v) => `${prefix}${v}`)
1050
- .join(',');
1051
- }
1052
- return `${prefix}${orderBy}`;
1053
- }
1054
- function buildApply(apply, { aliases, escape = false, }) {
1055
- const applyArray = Array.isArray(apply) ? apply : [apply];
1056
- return applyArray
1057
- .map((v) => normalizeValue(v, { aliases, escape }))
1058
- .join('/');
1059
- }
1060
- function buildUrl(path, params) {
1061
- // This can be refactored using URL API. But IE does not support it.
1062
- const queries = Object.entries(params).map(([key, value]) => `${key}=${value}`);
1063
- return queries.length ? `${path}?${queries.join('&')}` : path;
1064
- }
1065
- function parseNot(builtFilters) {
1066
- return `not (${builtFilters.join(' and ')})`;
1067
- }
1068
-
1069
- const ISO_REGEX = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
1070
- const Dates = {
1071
- isoStringToDate(value) {
1072
- if (typeof value === 'string' && value.search(ISO_REGEX) === 0) {
1073
- return new Date(value);
1074
- }
1075
- else if (Array.isArray(value)) {
1076
- return value.map((v) => this.isoStringToDate(v));
1077
- }
1078
- else if (value && value.constructor === Object) {
1079
- return Object.keys(value)
1080
- .map((key) => [key, this.isoStringToDate(value[key])])
1081
- .reduce((acc, v) => Object.assign(acc, { [v[0]]: v[1] }), {});
1082
- }
1083
- return value;
1084
- },
1085
- };
1086
-
1087
- const DURATION_REGEX = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
1088
- const Durations = {
1089
- toDuration(v) {
1090
- const matches = DURATION_REGEX.exec(v);
1091
- if (!matches || v.length < 3) {
1092
- throw new TypeError(`duration invalid: "${v}". Must be a ISO 8601 duration. See https://en.wikipedia.org/wiki/ISO_8601#Durations`);
1093
- }
1094
- let duration = {};
1095
- duration.sign = matches[1] === '-' ? -1 : 1;
1096
- return [
1097
- 'years',
1098
- 'months',
1099
- 'weeks',
1100
- 'days',
1101
- 'hours',
1102
- 'minutes',
1103
- 'seconds',
1104
- ].reduce((acc, name, index) => {
1105
- const v = parseFloat(matches[index + 2]);
1106
- if (!Number.isNaN(v))
1107
- acc[name] = v;
1108
- return acc;
1109
- }, duration);
1110
- },
1111
- toString(v) {
1112
- return [
1113
- v.sign === -1 ? '-' : '',
1114
- 'P',
1115
- v.years ? v.years + 'Y' : '',
1116
- v.months ? v.months + 'M' : '',
1117
- v.weeks ? v.weeks + 'W' : '',
1118
- v.days ? v.days + 'D' : '',
1119
- 'T',
1120
- v.hours ? v.hours + 'H' : '',
1121
- v.minutes ? v.minutes + 'M' : '',
1122
- v.seconds ? v.seconds + 'S' : '',
1123
- ].join('');
1124
- },
1125
- };
1126
-
1127
- const Enums = {
1128
- names(enums) {
1129
- return Object.values(enums).filter((v) => typeof v === 'string');
1130
- },
1131
- values(enums) {
1132
- return Object.values(enums).filter((v) => typeof v === 'number');
1133
- },
1134
- toValue(enums, value) {
1135
- if (value in enums)
1136
- return typeof value === 'string' ? enums[value] : value;
1137
- return undefined;
1138
- },
1139
- toValues(enums, value) {
1140
- if (typeof value === 'number') {
1141
- return this.values(enums).filter((v) => (value & v) === v);
1142
- }
1143
- if (typeof value === 'string') {
1144
- value = value.split(',').map((o) => o.trim());
1145
- }
1146
- if (Array.isArray(value) && value.every((v) => v in enums)) {
1147
- return value.map((o) => this.toValue(enums, o));
1148
- }
1149
- return [];
1150
- },
1151
- toName(enums, value) {
1152
- if (value in enums)
1153
- return typeof value === 'number' ? enums[value] : value;
1154
- return undefined;
1155
- },
1156
- toNames(enums, value) {
1157
- if (typeof value === 'number') {
1158
- return this.values(enums)
1159
- .filter((v) => (value & v) === v)
1160
- .map((v) => this.toName(enums, v));
1161
- }
1162
- if (typeof value === 'string') {
1163
- value = value.split(',').map((o) => o.trim());
1164
- }
1165
- if (Array.isArray(value) && value.every((v) => v in enums)) {
1166
- return value.map((o) => this.toName(enums, o));
1167
- }
1168
- return [];
1169
- },
1170
- toFlags(enums, value) {
1171
- if (typeof value === 'number') {
1172
- return this.values(enums)
1173
- .filter((v) => v !== 0 && (value & v) === v)
1174
- .map((v) => this.toName(enums, v));
1175
- }
1176
- if (typeof value === 'string') {
1177
- value = value.split(',').map((o) => o.trim());
1178
- }
1179
- if (Array.isArray(value) && value.every((v) => v in enums)) {
1180
- return value
1181
- .filter((v) => enums[v])
1182
- .map((v) => this.toName(enums, v));
1183
- }
1184
- return [];
1185
- },
1186
- };
1187
-
1188
- function cloneSymbol(targe) {
1189
- return Object(Symbol.prototype.valueOf.call(targe));
1190
- }
1191
- function cloneReg(targe) {
1192
- const reFlags = /\w*$/;
1193
- const result = new targe.constructor(targe.source, reFlags.exec(targe));
1194
- result.lastIndex = targe.lastIndex;
1195
- return result;
1196
- }
1197
- const Types = {
1198
- rawType(value) {
1199
- return Object.prototype.toString.call(value).slice(8, -1);
1200
- },
1201
- isObject(value) {
1202
- return typeof value === 'object' && value !== null;
1203
- },
1204
- isPlainObject(value) {
1205
- if (this.rawType(value) !== 'Object') {
1206
- return false;
1207
- }
1208
- const prototype = Object.getPrototypeOf(value);
1209
- return prototype === null || prototype === Object.prototype;
1210
- },
1211
- isFunction(value) {
1212
- return typeof value === 'function';
1213
- },
1214
- isArray(value) {
1215
- return Array.isArray(value);
1216
- },
1217
- isMap(value) {
1218
- return this.rawType(value) === 'Map';
1219
- },
1220
- isEmpty(value) {
1221
- return (value === undefined ||
1222
- value === null ||
1223
- (typeof value === 'string' && !value.length) ||
1224
- (value instanceof Date && isNaN(value.valueOf())) ||
1225
- (Types.isMap(value) && !value.size) ||
1226
- (Types.isArray(value) && !value.length) ||
1227
- (Types.isFunction(value.isEmpty) && value.isEmpty()) ||
1228
- (Types.isArray(value) &&
1229
- value.every((v) => Types.isEmpty(v))) ||
1230
- (Types.isPlainObject(value) &&
1231
- !Object.keys(value).filter((k) => value.hasOwnProperty(k)).length));
1232
- },
1233
- isEqual(value1, value2) {
1234
- function getType(obj) {
1235
- return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
1236
- }
1237
- function areDatesEqual() {
1238
- return value1.getTime() === value2.getTime();
1239
- }
1240
- function areArraysBufferEqual() {
1241
- if (value1.byteLength !== value2.byteLength) {
1242
- return false;
1243
- }
1244
- var view1 = new DataView(value1);
1245
- var view2 = new DataView(value2);
1246
- var i = value1.byteLength;
1247
- while (i--) {
1248
- if (view1.getUint8(i) !== view2.getUint8(i)) {
1249
- return false;
1250
- }
1251
- }
1252
- return true;
1253
- }
1254
- function areArraysEqual() {
1255
- // Check length
1256
- if (value1.length !== value2.length)
1257
- return false;
1258
- // Check each item in the array
1259
- for (let i = 0; i < value1.length; i++) {
1260
- if (!Types.isEqual(value1[i], value2[i]))
1261
- return false;
1262
- }
1263
- // If no errors, return true
1264
- return true;
1265
- }
1266
- function areObjectsEqual() {
1267
- if (Object.keys(value1).length !== Object.keys(value2).length)
1268
- return false;
1269
- // Check each item in the object
1270
- for (let key in value1) {
1271
- if (Object.prototype.hasOwnProperty.call(value1, key)) {
1272
- if (!Types.isEqual(value1[key], value2[key]))
1273
- return false;
1274
- }
1275
- }
1276
- // If no errors, return true
1277
- return true;
1278
- }
1279
- function areFunctionsEqual() {
1280
- return value1.toString() === value2.toString();
1281
- }
1282
- function arePrimativesEqual() {
1283
- return value1 === value2;
1284
- }
1285
- // Get the object type
1286
- let type = getType(value1);
1287
- // If the two items are not the same type, return false
1288
- if (type !== getType(value2))
1289
- return false;
1290
- // Compare based on type
1291
- if (type === 'date')
1292
- return areDatesEqual();
1293
- if (type === 'arraybuffer')
1294
- return areArraysBufferEqual();
1295
- if (type === 'array')
1296
- return areArraysEqual();
1297
- if (type === 'object')
1298
- return areObjectsEqual();
1299
- if (type === 'function')
1300
- return areFunctionsEqual();
1301
- return arePrimativesEqual();
222
+ const COLLECTION = /Collection\(([\w\.]+)\)/;
223
+ const PROPERTY = /([\w\d\-_]+)\(([\'\w\d\-_=]+)\)/;
224
+ const EXPAND = /([\w\d\-_]+)\(([\w\d\,\(\)]+)\)/;
225
+ const ODataVersionBaseHelper = {
226
+ entity(data) {
227
+ return data;
1302
228
  },
1303
- clone(target) {
1304
- const constrFun = target.constructor;
1305
- switch (this.rawType(target)) {
1306
- case 'Boolean':
1307
- case 'Number':
1308
- case 'String':
1309
- case 'Error':
1310
- case 'Date':
1311
- return new constrFun(target);
1312
- case 'RegExp':
1313
- return cloneReg(target);
1314
- case 'Symbol':
1315
- return cloneSymbol(target);
1316
- case 'Function':
1317
- return target;
1318
- default:
1319
- return null;
1320
- }
229
+ entities(data) {
230
+ return data[this.VALUE];
1321
231
  },
1322
- };
1323
-
1324
- const Http = {
1325
- //Merge Headers
1326
- mergeHttpHeaders(...values) {
1327
- let headers = new HttpHeaders();
1328
- values.forEach((value) => {
1329
- if (value instanceof HttpHeaders) {
1330
- value.keys().forEach((key) => {
1331
- headers = (value.getAll(key) || []).reduce((acc, v) => acc.append(key, v), headers);
1332
- });
1333
- }
1334
- else if (Types.isPlainObject(value)) {
1335
- Object.entries(value).forEach(([key, value]) => {
1336
- headers = (Array.isArray(value) ? value : [value]).reduce((acc, v) => acc.append(key, v), headers);
1337
- });
1338
- }
1339
- });
1340
- return headers;
232
+ property(data) {
233
+ return this.VALUE in data ? data[this.VALUE] : data;
1341
234
  },
1342
- // Merge Params
1343
- mergeHttpParams(...values) {
1344
- let params = new HttpParams();
1345
- values.forEach((value) => {
1346
- if (value instanceof HttpParams) {
1347
- value.keys().forEach((key) => {
1348
- params = (value.getAll(key) || []).reduce((acc, v) => acc.append(key, v), params);
1349
- });
1350
- }
1351
- else if (Types.isPlainObject(value)) {
1352
- Object.entries(value).forEach(([key, value]) => {
1353
- params = (Array.isArray(value) ? value : [value]).reduce((acc, v) => acc.append(key, v), params);
1354
- });
1355
- }
1356
- });
1357
- return params;
235
+ functions(annots) {
236
+ const funcs = new Map();
237
+ [...annots.keys()]
238
+ .filter((key) => key.startsWith(this.ODATA_FUNCTION_PREFIX))
239
+ .forEach((key) => funcs.set(key.substring(this.ODATA_FUNCTION_PREFIX.length), annots.get(key)));
240
+ return funcs;
1358
241
  },
1359
- // Split Params
1360
- splitHttpParams(params, keys) {
1361
- let other = new HttpParams();
1362
- params.keys().forEach((key) => {
1363
- if (keys.includes(key)) {
1364
- other = (params.getAll(key) || []).reduce((acc, v) => acc.append(key, v), other);
1365
- params = params.delete(key);
1366
- }
242
+ properties(annots) {
243
+ const props = new Map();
244
+ [...annots.keys()]
245
+ .filter((key) => key.indexOf(this.ODATA_ANNOTATION_PREFIX) > 0)
246
+ .forEach((key) => {
247
+ let name = key.substring(0, key.indexOf(this.ODATA_ANNOTATION_PREFIX));
248
+ let prop = props.has(name) ? props.get(name) : new Map();
249
+ prop.set(key.substring(key.indexOf(this.ODATA_ANNOTATION_PREFIX)), annots.get(key));
250
+ props.set(name, prop);
1367
251
  });
1368
- return [params, other];
252
+ return props;
1369
253
  },
1370
- // Without Params
1371
- withoutHttpParams(params, keys) {
1372
- return keys.reduce((acc, key) => acc.delete(key), params);
254
+ id(annots) {
255
+ return annots instanceof Map
256
+ ? annots.get(this.ODATA_ID)
257
+ : annots[this.ODATA_ID];
1373
258
  },
1374
- resolveHeaderKey(headers, options) {
1375
- if (headers instanceof HttpHeaders) {
1376
- return headers.keys().find((k) => options.indexOf(k) !== -1);
1377
- }
1378
- else if (Types.isPlainObject(headers)) {
1379
- return Object.keys(headers).find((k) => options.indexOf(k) !== -1);
1380
- }
1381
- return undefined;
259
+ etag(annots) {
260
+ return annots instanceof Map
261
+ ? annots.get(this.ODATA_ETAG)
262
+ : annots[this.ODATA_ETAG];
1382
263
  },
1383
- headerValue(header) {
1384
- let res = header.split(';')[0].trim();
1385
- res = res.split(':')[1].trim();
1386
- return res;
264
+ type(annots) {
265
+ let type = annots instanceof Map
266
+ ? annots.get(this.ODATA_TYPE)
267
+ : annots[this.ODATA_TYPE];
268
+ if (!type)
269
+ return undefined;
270
+ type = type.substring(1);
271
+ const matches = COLLECTION.exec(type);
272
+ if (matches)
273
+ return matches[1].indexOf('.') === -1 ? `Edm.${matches[1]}` : matches[1];
274
+ return type;
1387
275
  },
1388
- parseResponseStatus(line) {
1389
- const chunks = line.split(' ');
1390
- return {
1391
- status: chunks[0],
1392
- code: parseInt(chunks[1], 10),
1393
- message: chunks.slice(2).join(' '),
1394
- };
276
+ mediaEtag(annots) {
277
+ return annots.has(this.ODATA_MEDIA_ETAG)
278
+ ? decodeURIComponent(annots.get(this.ODATA_MEDIA_ETAG))
279
+ : undefined;
1395
280
  },
1396
- boundaryDelimiter(contentType) {
1397
- const contentTypeParts = contentType.split(';');
1398
- if (contentTypeParts.length === 2) {
1399
- const boundary = contentType.split(';')[1].trim();
1400
- const boundaryDelimiter = BOUNDARY_PREFIX_SUFFIX + boundary.split('=')[1];
1401
- return boundaryDelimiter;
1402
- }
1403
- else {
1404
- return '';
1405
- }
281
+ metadataEtag(annots) {
282
+ return annots.has(this.ODATA_METADATA_ETAG)
283
+ ? decodeURIComponent(annots.get(this.ODATA_METADATA_ETAG))
284
+ : undefined;
1406
285
  },
1407
- boundaryEnd(boundaryDelimiter) {
1408
- if (!boundaryDelimiter.length) {
1409
- return '';
1410
- }
1411
- const boundaryEnd = boundaryDelimiter + BOUNDARY_PREFIX_SUFFIX;
1412
- return boundaryEnd;
286
+ count(annots) {
287
+ return annots.has(this.ODATA_COUNT)
288
+ ? Number(annots.get(this.ODATA_COUNT))
289
+ : undefined;
1413
290
  },
1414
- };
1415
-
1416
- function forEach(array, iteratee) {
1417
- let index = -1;
1418
- const length = array.length;
1419
- while (++index < length) {
1420
- iteratee(array[index], index);
1421
- }
1422
- return array;
1423
- }
1424
- const Objects = {
1425
- set(obj, path, value) {
1426
- // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1427
- const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1428
- pathArray.reduce((acc, key, i) => {
1429
- if (acc[key] === undefined)
1430
- acc[key] = {};
1431
- if (i === pathArray.length - 1)
1432
- acc[key] = value;
1433
- return acc[key];
1434
- }, obj);
291
+ annotations(value) {
292
+ const annots = new Map();
293
+ Object.entries(value)
294
+ .filter(([key]) => key.indexOf(this.ODATA_ANNOTATION_PREFIX) !== -1 ||
295
+ key.startsWith(this.ODATA_FUNCTION_PREFIX))
296
+ .forEach(([key, value]) => annots.set(key, value));
297
+ return annots;
1435
298
  },
1436
- get(obj, path, def) {
1437
- // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1438
- const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1439
- // Find value if exist return otherwise return undefined value;
1440
- return (pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj) || def);
299
+ attributes(value, metadata) {
300
+ return Object.entries(value)
301
+ .filter(([k]) => metadata === 'none' ||
302
+ (metadata === 'minimal' &&
303
+ (k.indexOf(this.ODATA_ANNOTATION_PREFIX) === -1 ||
304
+ k.startsWith(this.ODATA_ANNOTATION_PREFIX)) &&
305
+ !k.startsWith(this.ODATA_FUNCTION_PREFIX)) ||
306
+ (metadata === 'full' &&
307
+ k.indexOf(this.ODATA_ANNOTATION_PREFIX) === -1 &&
308
+ !k.startsWith(this.ODATA_FUNCTION_PREFIX)))
309
+ .reduce((acc, e) => ({ ...acc, [e[0]]: e[1] }), {});
1441
310
  },
1442
- unset(obj, path) {
1443
- // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1444
- const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1445
- pathArray.reduce((acc, key, i) => {
1446
- if (i === pathArray.length - 1)
1447
- delete acc[key];
1448
- return acc[key];
1449
- }, obj);
311
+ nextLink(annots) {
312
+ return annots.has(this.ODATA_NEXTLINK)
313
+ ? decodeURIComponent(annots.get(this.ODATA_NEXTLINK))
314
+ : undefined;
1450
315
  },
1451
- has(obj, path) {
1452
- // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1453
- const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1454
- return !!pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
316
+ readLink(annots) {
317
+ return annots.has(this.ODATA_READLINK)
318
+ ? decodeURIComponent(annots.get(this.ODATA_READLINK))
319
+ : undefined;
1455
320
  },
1456
- merge(target, source) {
1457
- const merge = (target, source) => {
1458
- for (let attr in source) {
1459
- let value = source[attr];
1460
- if (value !== null && Types.isPlainObject(value) && attr in target) {
1461
- merge(target[attr], value);
1462
- }
1463
- else if (target[attr] !== value) {
1464
- target[attr] = value;
1465
- }
1466
- }
1467
- };
1468
- merge(target, source);
1469
- return target;
321
+ mediaReadLink(annots) {
322
+ return annots.has(this.ODATA_MEDIA_READLINK)
323
+ ? decodeURIComponent(annots.get(this.ODATA_MEDIA_READLINK))
324
+ : undefined;
1470
325
  },
1471
- equal(object1, object2) {
1472
- const keys1 = Object.keys(object1);
1473
- const keys2 = Object.keys(object2);
1474
- if (keys1.length !== keys2.length) {
1475
- return false;
1476
- }
1477
- for (const key of keys1) {
1478
- const val1 = object1[key];
1479
- const val2 = object2[key];
1480
- const areObjects = Types.isPlainObject(val1) && Types.isPlainObject(val2);
1481
- if ((areObjects && !Objects.equal(val1, val2)) ||
1482
- (!areObjects && val1 !== val2)) {
1483
- return false;
1484
- }
1485
- }
1486
- return true;
326
+ editLink(annots) {
327
+ return annots.has(this.ODATA_EDITLINK)
328
+ ? decodeURIComponent(annots.get(this.ODATA_EDITLINK))
329
+ : undefined;
1487
330
  },
1488
- difference(object1, object2) {
1489
- if (!object2 || !Types.isPlainObject(object2)) {
1490
- return object1;
1491
- }
1492
- var diffs = {};
1493
- var key;
1494
- var arraysMatch = function (arr1, arr2) {
1495
- if (arr1.length !== arr2.length)
1496
- return false;
1497
- for (var i = 0; i < arr1.length; i++) {
1498
- if (arr1[i] !== arr2[i])
1499
- return false;
1500
- }
1501
- return true;
1502
- };
1503
- var compare = function (item1, item2, key) {
1504
- if (item2 === undefined) {
1505
- diffs[key] = null;
1506
- return;
1507
- }
1508
- if (typeof item1 !== typeof item2) {
1509
- diffs[key] = item2;
1510
- return;
1511
- }
1512
- if (Types.isPlainObject(item1)) {
1513
- var objDiff = Objects.difference(item1, item2);
1514
- if (Object.keys(objDiff).length > 0) {
1515
- diffs[key] = objDiff;
331
+ mediaEditLink(annots) {
332
+ return annots.has(this.ODATA_MEDIA_EDITLINK)
333
+ ? decodeURIComponent(annots.get(this.ODATA_MEDIA_EDITLINK))
334
+ : undefined;
335
+ },
336
+ deltaLink(annots) {
337
+ return annots.has(this.ODATA_DELTALINK)
338
+ ? decodeURIComponent(annots.get(this.ODATA_DELTALINK))
339
+ : undefined;
340
+ },
341
+ mediaContentType(annots) {
342
+ return annots.has(this.ODATA_MEDIA_CONTENTTYPE)
343
+ ? decodeURIComponent(annots.get(this.ODATA_MEDIA_CONTENTTYPE))
344
+ : undefined;
345
+ },
346
+ };
347
+ const ODataHelper = {
348
+ //#region Version 4.0
349
+ [VERSION_4_0]: {
350
+ ...ODataVersionBaseHelper,
351
+ VALUE: 'value',
352
+ ODATA_ANNOTATION_PREFIX: '@odata',
353
+ ODATA_FUNCTION_PREFIX: '#',
354
+ //odata.id: the ID of the entity
355
+ ODATA_ID: '@odata.id',
356
+ //odata.count: the total count of a collection of entities or collection of entity references, if requested.
357
+ ODATA_COUNT: '@odata.count',
358
+ //odata.context: the context URL for a collection, entity, primitive value, or service document.
359
+ ODATA_CONTEXT: '@odata.context',
360
+ //odata.etag: the ETag of the entity
361
+ ODATA_ETAG: '@odata.etag',
362
+ ODATA_METADATA_ETAG: '@odata.metadataEtag',
363
+ //odata.type: the type of the containing {[name: string]: any} or targeted property if the type of the {[name: string]: any} or targeted property cannot be heuristically determined
364
+ ODATA_TYPE: '@odata.type',
365
+ //odata.delta
366
+ ODATA_DELTA: '@odata.delta',
367
+ //odata.remove
368
+ ODATA_REMOVE: '@odata.remove',
369
+ //odata.nextLink: the next link of a collection with partial results
370
+ ODATA_NEXTLINK: '@odata.nextLink',
371
+ //odata.deltaLink: the delta link for obtaining changes to the result, if requested
372
+ ODATA_DELTALINK: '@odata.deltaLink',
373
+ //odata.readLink: the link used to read the entity, if the edit link cannot be used to read the entity
374
+ ODATA_READLINK: '@odata.readLink',
375
+ //odata.editLink: the link used to edit/update the entity, if the entity is updatable and the odata.id does not represent a URL that can be used to edit the entity
376
+ ODATA_EDITLINK: '@odata.editLink',
377
+ //odata.associationLink: the link used to describe the relationship between this entity and related entities
378
+ ODATA_ASSOCIATIONLINK: '@odata.associationLink',
379
+ //odata.navigationLink: the link used to retrieve the values of a navigation property
380
+ ODATA_NAVIGATIONLINK: '@odata.navigationLink',
381
+ //Media entities and stream properties may in addition contain the following annotations:
382
+ //odata.mediaEtag: the ETag of the stream, as appropriate
383
+ ODATA_MEDIA_ETAG: '@odata.mediaEtag',
384
+ //odata.mediaContentType: the content type of the stream
385
+ ODATA_MEDIA_CONTENTTYPE: '@odata.mediaContentType',
386
+ //odata.mediaReadLink: the link used to read the stream
387
+ ODATA_MEDIA_READLINK: '@odata.mediaReadLink',
388
+ //odata.mediaEditLink: the link used to edit/update the stream
389
+ ODATA_MEDIA_EDITLINK: '@odata.mediaEditLink',
390
+ //http://nb-mdp-dev01:57970/$metadata#recursos/$entity
391
+ //http://nb-mdp-dev01:57970/$metadata#categorias
392
+ //http://nb-mdp-dev01:57970/$metadata#juzgados
393
+ //http://nb-mdp-dev01:57970/$metadata#Collection(SIU.Recursos.RecursoEntry)
394
+ //http://nb-mdp-dev01:57970/$metadata#categorias/$entity
395
+ //http://nb-mdp-dev01:57970/$metadata#categorias(children(children(children(children(children(children(children(children(children(children()))))))))))/$entity
396
+ //http://nb-mdp-dev01:57970/$metadata#recursos/SIU.Documentos.Documento/$entity
397
+ //http://nb-mdp-dev01:57970/$metadata#SIU.Api.Infrastructure.Storage.Backend.SiuUrls
398
+ context(annots) {
399
+ let ctx = {};
400
+ const str = annots instanceof Map
401
+ ? annots.get(this.ODATA_CONTEXT)
402
+ : annots[this.ODATA_CONTEXT];
403
+ if (typeof str === 'string') {
404
+ let index = str.indexOf('$metadata');
405
+ ctx.serviceRootUrl = str.substring(0, index);
406
+ index = str.indexOf('#');
407
+ ctx.metadataUrl = str.substring(0, index);
408
+ const parts = str.substring(index + 1).split('/');
409
+ const col = COLLECTION.exec(parts[0]);
410
+ if (col) {
411
+ ctx.type = col[1];
1516
412
  }
1517
- return;
1518
- }
1519
- if (Array.isArray(item1)) {
1520
- if (!arraysMatch(item1, item2)) {
1521
- diffs[key] = item2;
413
+ else if (parts[0].indexOf('.') !== -1) {
414
+ ctx.type = parts[0];
1522
415
  }
1523
- return;
1524
- }
1525
- if (item1 !== item2) {
1526
- diffs[key] = item2;
1527
- }
1528
- };
1529
- for (key in object1) {
1530
- if (object1.hasOwnProperty(key)) {
1531
- compare(object1[key], object2[key], key);
1532
- }
1533
- }
1534
- for (key in object2) {
1535
- if (object2.hasOwnProperty(key)) {
1536
- if (!object1[key] && object1[key] !== object2[key]) {
1537
- diffs[key] = object2[key];
416
+ else {
417
+ const property = parts[0].match(PROPERTY);
418
+ const expand = parts[0].match(EXPAND);
419
+ ctx.entity = parts[1] === '$entity';
420
+ if (property) {
421
+ ctx.entitySet = property[1];
422
+ ctx.key = property[2];
423
+ ctx.property = parts[1];
424
+ }
425
+ else if (expand) {
426
+ ctx.entitySet = expand[1];
427
+ ctx.expand = expand[2];
428
+ }
429
+ else {
430
+ ctx.entitySet = parts[0];
431
+ }
1538
432
  }
1539
433
  }
1540
- }
1541
- return diffs;
434
+ return ctx;
435
+ },
436
+ countParam() {
437
+ return { [$COUNT]: 'true' };
438
+ },
439
+ },
440
+ //#endregion
441
+ //#region Version 3.0
442
+ [VERSION_3_0]: {
443
+ ...ODataVersionBaseHelper,
444
+ ODATA_ANNOTATION_PREFIX: 'odata.',
445
+ ODATA_FUNCTION_PREFIX: '',
446
+ ODATA_ID: 'odata.id',
447
+ ODATA_DELTA: 'odata.delta',
448
+ ODATA_REMOVE: 'odata.remove',
449
+ ODATA_ETAG: 'odata.etag',
450
+ ODATA_CONTEXT: 'odata.metadata',
451
+ ODATA_NEXTLINK: 'odata.nextLink',
452
+ ODATA_TYPE: 'odata.type',
453
+ ODATA_COUNT: 'odata.count',
454
+ VALUE: 'value',
455
+ context(annots) {
456
+ let ctx = {};
457
+ const str = annots instanceof Map
458
+ ? annots.get(this.ODATA_CONTEXT)
459
+ : annots[this.ODATA_CONTEXT];
460
+ if (typeof str === 'string') {
461
+ let index = str.indexOf('$metadata');
462
+ ctx.serviceRootUrl = str.substring(0, index);
463
+ index = str.indexOf('#');
464
+ ctx.metadataUrl = str.substring(0, index);
465
+ const parts = str.substring(index + 1).split('/');
466
+ ctx.entitySet = parts[0];
467
+ }
468
+ return ctx;
469
+ },
470
+ countParam() {
471
+ return { [$INLINECOUNT]: 'allpages' };
472
+ },
1542
473
  },
1543
- resolveKey(key, { single = true } = {}) {
1544
- const type = Types.rawType(key);
1545
- if (['number', 'string'].indexOf(type) !== -1)
1546
- return key;
1547
- if (type !== 'Map' && type !== 'Object') {
1548
- return undefined;
1549
- }
1550
- const values = type === 'Map' ? Array.from(key.values()) : Object.values(key);
1551
- if (values.length === 1 && single) {
1552
- // Single primitive key value
1553
- key = values[0];
1554
- return !Types.isEmpty(key) ? key : undefined;
1555
- }
1556
- else if (values.some((v) => v === undefined)) {
1557
- // Compose key, needs all values
1558
- return undefined;
1559
- }
1560
- else {
1561
- const obj = type === 'Map' ? Object.fromEntries(key) : key;
1562
- return !Types.isEmpty(obj) ? obj : undefined;
1563
- }
474
+ //#endregion
475
+ //#region Version 2.0
476
+ [VERSION_2_0]: {
477
+ ...ODataVersionBaseHelper,
478
+ ODATA_ID: 'id',
479
+ ODATA_DELTA: 'delta',
480
+ ODATA_REMOVE: 'remove',
481
+ ODATA_ETAG: 'etag',
482
+ ODATA_ANNOTATION: '__metadata',
483
+ ODATA_NEXTLINK: '__next',
484
+ ODATA_COUNT: '__count',
485
+ ODATA_DEFERRED: '__deferred',
486
+ ODATA_TYPE: 'type',
487
+ VALUE: 'results',
488
+ annotations(value) {
489
+ const annots = new Map();
490
+ if (this.ODATA_ANNOTATION in value) {
491
+ Object.entries(value[this.ODATA_ANNOTATION]).forEach(([key, value]) => annots.set(key, value));
492
+ }
493
+ return annots;
494
+ },
495
+ context(annots) {
496
+ let ctx = {};
497
+ return ctx;
498
+ },
499
+ attributes(value, metadata) {
500
+ return value;
501
+ },
502
+ countParam() {
503
+ return { [$INLINECOUNT]: 'allpages' };
504
+ },
1564
505
  },
1565
- clone(target, map) {
1566
- if (map === undefined)
1567
- map = new WeakMap();
1568
- // clone primitive types
1569
- if (typeof target != 'object' || target == null) {
1570
- return target;
1571
- }
1572
- if ('clone' in target) {
1573
- // target is a cloneable object
1574
- return target.clone();
1575
- }
1576
- const type = Types.rawType(target);
1577
- let cloneTarget = null;
1578
- if (map.get(target)) {
1579
- return map.get(target);
1580
- }
1581
- map.set(target, cloneTarget);
1582
- if (type != 'Set' && type != 'Map' && type != 'Array' && type != 'Object') {
1583
- return Types.clone(target);
506
+ //#endregion
507
+ };
508
+
509
+ const COMPARISON_OPERATORS = ['eq', 'ne', 'gt', 'ge', 'lt', 'le'];
510
+ const LOGICAL_OPERATORS = ['and', 'or', 'not'];
511
+ const COLLECTION_OPERATORS = ['any', 'all'];
512
+ const BOOLEAN_FUNCTIONS = ['startswith', 'endswith', 'contains'];
513
+ const SUPPORTED_EXPAND_PROPERTIES = [
514
+ 'expand',
515
+ 'levels',
516
+ 'select',
517
+ 'top',
518
+ 'count',
519
+ 'orderby',
520
+ 'filter',
521
+ ];
522
+ const FUNCTION_REGEX = /\((.*)\)/;
523
+ const INDEXOF_REGEX = /(?!indexof)\((\w+)\)/;
524
+ var StandardAggregateMethods;
525
+ (function (StandardAggregateMethods) {
526
+ StandardAggregateMethods["sum"] = "sum";
527
+ StandardAggregateMethods["min"] = "min";
528
+ StandardAggregateMethods["max"] = "max";
529
+ StandardAggregateMethods["average"] = "average";
530
+ StandardAggregateMethods["countdistinct"] = "countdistinct";
531
+ })(StandardAggregateMethods || (StandardAggregateMethods = {}));
532
+ var QueryCustomTypes;
533
+ (function (QueryCustomTypes) {
534
+ QueryCustomTypes[QueryCustomTypes["Raw"] = 0] = "Raw";
535
+ QueryCustomTypes[QueryCustomTypes["Alias"] = 1] = "Alias";
536
+ QueryCustomTypes[QueryCustomTypes["Duration"] = 2] = "Duration";
537
+ QueryCustomTypes[QueryCustomTypes["Binary"] = 3] = "Binary";
538
+ })(QueryCustomTypes || (QueryCustomTypes = {}));
539
+ //https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_QueryOptions
540
+ const raw = (value) => ({
541
+ type: QueryCustomTypes.Raw,
542
+ value,
543
+ });
544
+ const alias = (value, name) => ({
545
+ type: QueryCustomTypes.Alias,
546
+ value,
547
+ name,
548
+ });
549
+ const duration = (value) => ({
550
+ type: QueryCustomTypes.Duration,
551
+ value,
552
+ });
553
+ const binary = (value) => ({
554
+ type: QueryCustomTypes.Binary,
555
+ value,
556
+ });
557
+ const isQueryCustomType = (value) => typeof value === 'object' &&
558
+ 'type' in value &&
559
+ value.type in QueryCustomTypes;
560
+ const isRawType = (value) => isQueryCustomType(value) &&
561
+ value.type === QueryCustomTypes.Raw;
562
+ const ITEM_ROOT = '';
563
+ function builder ({ select, search, skiptoken, format, top, skip, filter, transform, compute, orderBy, key, count, expand, action, func, aliases, escape, } = {}) {
564
+ const [path, params] = buildPathAndQuery({
565
+ select,
566
+ search,
567
+ skiptoken,
568
+ format,
569
+ top,
570
+ skip,
571
+ filter,
572
+ transform,
573
+ compute,
574
+ orderBy,
575
+ key,
576
+ count,
577
+ expand,
578
+ action,
579
+ func,
580
+ aliases,
581
+ escape,
582
+ });
583
+ return buildUrl(path, params);
584
+ }
585
+ function buildPathAndQuery({ select, search, skiptoken, format, top, skip, filter, apply, transform, compute, orderBy, key, count, expand, action, func, aliases, escape, } = {}) {
586
+ let path = '';
587
+ aliases = aliases || [];
588
+ const query = {};
589
+ // key is not (null, undefined)
590
+ if (key != undefined) {
591
+ path += `(${normalizeValue(key, { aliases, escape })})`;
592
+ }
593
+ // Select
594
+ if (select) {
595
+ query.$select = isRawType(select)
596
+ ? select.value
597
+ : Array.isArray(select)
598
+ ? select.join(',')
599
+ : select;
600
+ }
601
+ // Compute
602
+ if (compute) {
603
+ query.$compute = isRawType(compute)
604
+ ? compute.value
605
+ : Array.isArray(compute)
606
+ ? compute.join(',')
607
+ : compute;
608
+ }
609
+ // Search
610
+ if (search) {
611
+ query.$search = search;
612
+ }
613
+ // Skiptoken
614
+ if (skiptoken) {
615
+ query.$skiptoken = skiptoken;
616
+ }
617
+ // Format
618
+ if (format) {
619
+ query.$format = format;
620
+ }
621
+ // Filter
622
+ if (filter || typeof count === 'object') {
623
+ query.$filter = buildFilter(typeof count === 'object' ? count : filter, {
624
+ aliases,
625
+ escape,
626
+ });
627
+ }
628
+ // Transform
629
+ if (transform) {
630
+ query.$apply = buildTransforms(transform, { aliases, escape });
631
+ }
632
+ // Apply
633
+ if (apply) {
634
+ query.$apply = query.$apply
635
+ ? query.$apply + '/' + buildApply(apply, { aliases, escape })
636
+ : buildApply(apply, { aliases, escape });
637
+ }
638
+ // Expand
639
+ if (expand) {
640
+ query.$expand = buildExpand(expand, { aliases, escape });
641
+ }
642
+ // OrderBy
643
+ if (orderBy) {
644
+ query.$orderby = buildOrderBy(orderBy);
645
+ }
646
+ // Count
647
+ if (isRawType(count)) {
648
+ query.$count = count.value;
649
+ }
650
+ else if (typeof count === 'boolean') {
651
+ query.$count = true;
652
+ }
653
+ else if (count) {
654
+ path += '/$count';
655
+ }
656
+ // Top
657
+ if (isRawType(top)) {
658
+ query.$top = top.value;
659
+ }
660
+ else if (typeof top === 'number') {
661
+ query.$top = top;
662
+ }
663
+ // Skip
664
+ if (isRawType(skip)) {
665
+ query.$top = skip.value;
666
+ }
667
+ else if (typeof skip === 'number') {
668
+ query.$skip = skip;
669
+ }
670
+ if (action) {
671
+ path += `/${action}`;
672
+ }
673
+ if (func) {
674
+ if (typeof func === 'string') {
675
+ path += `/${func}()`;
1584
676
  }
1585
- // clone Set
1586
- if (type == 'Set') {
1587
- cloneTarget = new Set();
1588
- target.forEach((value) => {
1589
- cloneTarget.add(this.clone(value, map));
677
+ else if (typeof func === 'object') {
678
+ const [funcName] = Object.keys(func);
679
+ const funcArgs = normalizeValue(func[funcName], {
680
+ aliases,
681
+ escape,
1590
682
  });
1591
- return cloneTarget;
683
+ path += `/${funcName}(${funcArgs})`;
1592
684
  }
1593
- // clone Map
1594
- if (type == 'Map') {
1595
- cloneTarget = new Map();
1596
- target.forEach((value, key) => {
1597
- cloneTarget.set(key, this.clone(value, map));
685
+ }
686
+ if (aliases.length > 0) {
687
+ Object.assign(query, aliases.reduce((acc, alias) => Object.assign(acc, {
688
+ [`@${alias.name}`]: normalizeValue(alias.value, {
689
+ escape,
690
+ }),
691
+ }), {}));
692
+ }
693
+ // Filter empty values
694
+ const params = Object.entries(query)
695
+ .filter(([, value]) => value !== undefined && value !== '')
696
+ .reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), {});
697
+ return [path, params];
698
+ }
699
+ function renderPrimitiveValue(key, val, { aliases, escape, }) {
700
+ return `${key} eq ${normalizeValue(val, { aliases, escape })}`;
701
+ }
702
+ function buildFilter(filters = {}, { aliases, propPrefix, escape, }) {
703
+ return (Array.isArray(filters) ? filters : [filters]).reduce((acc, filter) => {
704
+ if (filter) {
705
+ const builtFilter = buildFilterCore(filter, {
706
+ aliases,
707
+ propPrefix,
708
+ escape,
1598
709
  });
1599
- return cloneTarget;
710
+ if (builtFilter) {
711
+ acc.push(builtFilter);
712
+ }
1600
713
  }
1601
- // clone Array
1602
- if (type == 'Array') {
1603
- cloneTarget = new Array();
1604
- forEach(target, (value, index) => {
1605
- cloneTarget[index] = this.clone(value, map);
1606
- });
714
+ return acc;
715
+ }, []).join(' and ');
716
+ function buildFilterCore(filter = {}, { aliases, propPrefix, escape, }) {
717
+ let filterExpr = '';
718
+ if (isRawType(filter)) {
719
+ // Use raw query custom filter string
720
+ filterExpr = filter.value;
1607
721
  }
1608
- // clone normal Object
1609
- if (type == 'Object') {
1610
- cloneTarget = new Object();
1611
- forEach(Object.keys(target), (key, index) => {
1612
- cloneTarget[key] = this.clone(target[key], map);
1613
- });
722
+ else if (typeof filter === 'string') {
723
+ // Use raw filter string
724
+ filterExpr = filter;
1614
725
  }
1615
- return cloneTarget;
1616
- },
1617
- };
1618
-
1619
- const OData = {
1620
- // Merge callables parameters
1621
- mergeCallableParameters(callables) {
1622
- const areEqual = (a, b) => a.name === b.name &&
1623
- Objects.equal((a.parameters || {})[CALLABLE_BINDING_PARAMETER] || {}, (b.parameters || {})[CALLABLE_BINDING_PARAMETER] || {});
1624
- return callables.reduce((acc, config) => {
1625
- if (acc.every((c) => !areEqual(c, config))) {
1626
- config = callables
1627
- .filter((c) => areEqual(c, config))
1628
- .reduce((acc, c) => {
1629
- acc.parameters = Object.assign(acc.parameters || {}, c.parameters || {});
1630
- return acc;
1631
- }, config);
1632
- return [...acc, config];
1633
- }
1634
- return acc;
1635
- }, []);
1636
- },
1637
- };
1638
-
1639
- // From https://github.com/adamhalasz/uniqid
1640
- var glast;
1641
- function now() {
1642
- let time = Date.now();
1643
- let last = glast || time;
1644
- return (glast = time > last ? time : last + 1);
726
+ else if (filter && typeof filter === 'object') {
727
+ const filtersArray = Object.keys(filter).reduce((result, filterKey) => {
728
+ const value = filter[filterKey];
729
+ let propName = '';
730
+ if (propPrefix) {
731
+ if (filterKey === ITEM_ROOT) {
732
+ propName = propPrefix;
733
+ }
734
+ else if (INDEXOF_REGEX.test(filterKey)) {
735
+ propName = filterKey.replace(INDEXOF_REGEX, (_, $1) => $1.trim() === ITEM_ROOT
736
+ ? `(${propPrefix})`
737
+ : `(${propPrefix}/${$1.trim()})`);
738
+ }
739
+ else if (FUNCTION_REGEX.test(filterKey)) {
740
+ propName = filterKey.replace(FUNCTION_REGEX, (_, $1) => $1.trim() === ITEM_ROOT
741
+ ? `(${propPrefix})`
742
+ : `(${propPrefix}/${$1.trim()})`);
743
+ }
744
+ else {
745
+ propName = `${propPrefix}/${filterKey}`;
746
+ }
747
+ }
748
+ else {
749
+ propName = filterKey;
750
+ }
751
+ if (filterKey === ITEM_ROOT && Array.isArray(value)) {
752
+ return result.concat(value.map((arrayValue) => renderPrimitiveValue(propName, arrayValue, { escape, aliases })));
753
+ }
754
+ if (['number', 'string', 'boolean'].indexOf(typeof value) !== -1 ||
755
+ value instanceof Date ||
756
+ value === null) {
757
+ // Simple key/value handled as equals operator
758
+ result.push(renderPrimitiveValue(propName, value, { aliases, escape }));
759
+ }
760
+ else if (Array.isArray(value)) {
761
+ const op = filterKey;
762
+ const builtFilters = value
763
+ .map((v) => buildFilter(v, { aliases, propPrefix, escape }))
764
+ .filter((f) => f)
765
+ .map((f) => LOGICAL_OPERATORS.indexOf(op) !== -1 ? `(${f})` : f);
766
+ if (builtFilters.length) {
767
+ if (LOGICAL_OPERATORS.indexOf(op) !== -1) {
768
+ if (builtFilters.length) {
769
+ if (op === 'not') {
770
+ result.push(parseNot(builtFilters));
771
+ }
772
+ else {
773
+ result.push(`(${builtFilters.join(` ${op} `)})`);
774
+ }
775
+ }
776
+ }
777
+ else {
778
+ result.push(builtFilters.join(` ${op} `));
779
+ }
780
+ }
781
+ }
782
+ else if (LOGICAL_OPERATORS.indexOf(propName) !== -1) {
783
+ const op = propName;
784
+ const builtFilters = Object.keys(value).map((valueKey) => buildFilterCore({ [valueKey]: value[valueKey] }, { aliases, escape }));
785
+ if (builtFilters.length) {
786
+ if (op === 'not') {
787
+ result.push(parseNot(builtFilters));
788
+ }
789
+ else {
790
+ result.push(`${builtFilters.join(` ${op} `)}`);
791
+ }
792
+ }
793
+ }
794
+ else if (typeof value === 'object') {
795
+ if ('type' in value) {
796
+ result.push(renderPrimitiveValue(propName, value, { aliases, escape }));
797
+ }
798
+ else {
799
+ const operators = Object.keys(value);
800
+ operators.forEach((op) => {
801
+ if (COMPARISON_OPERATORS.indexOf(op) !== -1) {
802
+ result.push(`${propName} ${op} ${normalizeValue(value[op], {
803
+ aliases,
804
+ escape,
805
+ })}`);
806
+ }
807
+ else if (LOGICAL_OPERATORS.indexOf(op) !== -1) {
808
+ if (Array.isArray(value[op])) {
809
+ result.push(value[op]
810
+ .map((v) => '(' +
811
+ buildFilterCore(v, {
812
+ aliases,
813
+ propPrefix: propName,
814
+ escape,
815
+ }) +
816
+ ')')
817
+ .join(` ${op} `));
818
+ }
819
+ else {
820
+ result.push('(' +
821
+ buildFilterCore(value[op], {
822
+ aliases,
823
+ propPrefix: propName,
824
+ escape,
825
+ }) +
826
+ ')');
827
+ }
828
+ }
829
+ else if (COLLECTION_OPERATORS.indexOf(op) !== -1) {
830
+ const collectionClause = buildCollectionClause(filterKey.toLowerCase(), value[op], op, propName);
831
+ if (collectionClause) {
832
+ result.push(collectionClause);
833
+ }
834
+ }
835
+ else if (op === 'has') {
836
+ result.push(`${propName} ${op} ${normalizeValue(value[op], {
837
+ aliases,
838
+ escape,
839
+ })}`);
840
+ }
841
+ else if (op === 'in') {
842
+ const resultingValues = Array.isArray(value[op])
843
+ ? value[op]
844
+ : value[op].value.map((typedValue) => ({
845
+ type: value[op].type,
846
+ value: typedValue,
847
+ }));
848
+ result.push(propName +
849
+ ' in (' +
850
+ resultingValues
851
+ .map((v) => normalizeValue(v, { aliases, escape }))
852
+ .join(',') +
853
+ ')');
854
+ }
855
+ else if (BOOLEAN_FUNCTIONS.indexOf(op) !== -1) {
856
+ // Simple boolean functions (startswith, endswith, contains)
857
+ result.push(`${op}(${propName},${normalizeValue(value[op], {
858
+ aliases,
859
+ escape,
860
+ })})`);
861
+ }
862
+ else {
863
+ // Nested property
864
+ const filter = buildFilterCore(value, {
865
+ aliases,
866
+ propPrefix: propName,
867
+ escape,
868
+ });
869
+ if (filter) {
870
+ result.push(filter);
871
+ }
872
+ }
873
+ });
874
+ }
875
+ }
876
+ else if (value === undefined) {
877
+ // Ignore/omit filter if value is `undefined`
878
+ }
879
+ else {
880
+ throw new Error(`Unexpected value type: ${value}`);
881
+ }
882
+ return result;
883
+ }, []);
884
+ filterExpr = filtersArray.join(' and ');
885
+ } /* else {
886
+ throw new Error(`Unexpected filters type: ${filter}`);
887
+ } */
888
+ return filterExpr;
889
+ }
890
+ function buildCollectionClause(lambdaParameter, value, op, propName) {
891
+ let clause = '';
892
+ if (typeof value === 'string' || value instanceof String) {
893
+ clause = getStringCollectionClause(lambdaParameter, value, op, propName);
894
+ }
895
+ else if (value) {
896
+ // normalize {any:[{prop1: 1}, {prop2: 1}]} --> {any:{prop1: 1, prop2: 1}}; same for 'all',
897
+ // simple values collection: {any:[{'': 'simpleVal1'}, {'': 'simpleVal2'}]} --> {any:{'': ['simpleVal1', 'simpleVal2']}}; same for 'all',
898
+ const filterValue = Array.isArray(value)
899
+ ? value.reduce((acc, item) => {
900
+ if (item.hasOwnProperty(ITEM_ROOT)) {
901
+ if (!acc.hasOwnProperty(ITEM_ROOT)) {
902
+ acc[ITEM_ROOT] = [];
903
+ }
904
+ acc[ITEM_ROOT].push(item[ITEM_ROOT]);
905
+ return acc;
906
+ }
907
+ return { ...acc, ...item };
908
+ }, {})
909
+ : value;
910
+ const filter = buildFilterCore(filterValue, {
911
+ aliases,
912
+ propPrefix: lambdaParameter,
913
+ escape,
914
+ });
915
+ clause = `${propName}/${op}(${filter ? `${lambdaParameter}:${filter}` : ''})`;
916
+ }
917
+ return clause;
918
+ }
1645
919
  }
1646
- const Strings = {
1647
- uniqueId({ prefix, suffix, } = {}) {
1648
- return (prefix ? prefix : '') + now().toString(36) + (suffix ? suffix : '');
1649
- },
1650
- titleCase(text) {
1651
- const result = text.replace(/([a-z])([A-Z])/g, '$1 $2');
1652
- return result
1653
- .split(' ')
1654
- .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
1655
- .join(' ');
1656
- },
1657
- };
1658
-
1659
- const Urls = {
1660
- parseQueryString(query) {
1661
- return query.split(PARAM_SEPARATOR).reduce((acc, param) => {
1662
- let index = param.indexOf(VALUE_SEPARATOR);
1663
- if (index !== -1)
1664
- Object.assign(acc, {
1665
- [param.substring(0, index)]: param.substring(index + 1),
1666
- });
1667
- return acc;
1668
- }, {});
1669
- },
1670
- escapeIllegalChars(string) {
1671
- string = string.replace(/%/g, '%25');
1672
- string = string.replace(/\+/g, '%2B');
1673
- string = string.replace(/\//g, '%2F');
1674
- string = string.replace(/\?/g, '%3F');
1675
- string = string.replace(/#/g, '%23');
1676
- string = string.replace(/&/g, '%26');
1677
- string = string.replace(/'/g, "''");
1678
- return string;
1679
- },
1680
- };
1681
-
1682
- class Expression {
1683
- _children;
1684
- constructor({ children, } = {}) {
1685
- this._children = children || [];
920
+ function getStringCollectionClause(lambdaParameter, value, collectionOperator, propName) {
921
+ let clause = '';
922
+ const conditionOperator = collectionOperator == 'all' ? 'ne' : 'eq';
923
+ clause = `${propName}/${collectionOperator}(${lambdaParameter}: ${lambdaParameter} ${conditionOperator} '${value}')`;
924
+ return clause;
925
+ }
926
+ function escapeIllegalChars(string) {
927
+ string = string.replace(/%/g, '%25');
928
+ string = string.replace(/\+/g, '%2B');
929
+ string = string.replace(/\//g, '%2F');
930
+ string = string.replace(/\?/g, '%3F');
931
+ string = string.replace(/#/g, '%23');
932
+ string = string.replace(/&/g, '%26');
933
+ string = string.replace(/'/g, "''");
934
+ return string;
935
+ }
936
+ function normalizeValue(value, { aliases, escape = false, } = {}) {
937
+ if (typeof value === 'string') {
938
+ return escape ? `'${escapeIllegalChars(value)}'` : `'${value}'`;
1686
939
  }
1687
- get [Symbol.toStringTag]() {
1688
- return 'Expression';
940
+ else if (value instanceof Date) {
941
+ return value.toISOString();
1689
942
  }
1690
- children() {
1691
- return this._children;
943
+ else if (typeof value === 'number') {
944
+ return value;
1692
945
  }
1693
- length() {
1694
- return this._children.length;
946
+ else if (Array.isArray(value)) {
947
+ return `[${value
948
+ .map((d) => normalizeValue(d, { aliases, escape }))
949
+ .join(',')}]`;
1695
950
  }
1696
- toJson() {
1697
- return {
1698
- $type: Types.rawType(this),
1699
- children: this._children.map((c) => c.toJson()),
1700
- };
951
+ else if (value === null) {
952
+ return value;
1701
953
  }
1702
- resolve(parser) {
1703
- return parser;
954
+ else if (typeof value === 'object') {
955
+ switch (value.type) {
956
+ case QueryCustomTypes.Raw:
957
+ return value.value;
958
+ case QueryCustomTypes.Duration:
959
+ return `duration'${value.value}'`;
960
+ case QueryCustomTypes.Binary:
961
+ return `binary'${value.value}'`;
962
+ case QueryCustomTypes.Alias:
963
+ // Store
964
+ if (Array.isArray(aliases)) {
965
+ if (value.name === undefined) {
966
+ value.name = `a${aliases.length + 1}`;
967
+ }
968
+ aliases.push(value);
969
+ }
970
+ return `@${value.name}`;
971
+ default:
972
+ return Object.entries(value)
973
+ .filter(([, v]) => v !== undefined)
974
+ .map(([k, v]) => `${k}=${normalizeValue(v, { aliases, escape })}`)
975
+ .join(',');
976
+ }
1704
977
  }
978
+ return value;
1705
979
  }
1706
-
1707
- class ODataAnnotation {
1708
- term;
1709
- string;
1710
- bool;
1711
- int;
1712
- permissions;
1713
- properties;
1714
- constructor(annot) {
1715
- this.term = annot.term;
1716
- Object.assign(this, annot);
980
+ function buildExpand(expands, { aliases, escape = false, }) {
981
+ if (isRawType(expands)) {
982
+ return expands.value;
1717
983
  }
1718
- }
1719
- class ODataAnnotatable {
1720
- annotations;
1721
- constructor(config) {
1722
- this.annotations = (config.annotations || []).map((annot) => new ODataAnnotation(annot));
984
+ else if (typeof expands === 'number') {
985
+ return expands;
1723
986
  }
1724
- /**
1725
- * Find an annotation inside the annotatable.
1726
- * @param predicate Function that returns true if the annotation match.
1727
- * @returns The annotation that matches the predicate.
1728
- */
1729
- findAnnotation(predicate) {
1730
- return this.annotations.find(predicate);
987
+ else if (typeof expands === 'string') {
988
+ if (expands.indexOf('/') === -1) {
989
+ return expands;
990
+ }
991
+ // Change `Foo/Bar/Baz` to `Foo($expand=Bar($expand=Baz))`
992
+ return expands
993
+ .split('/')
994
+ .reverse()
995
+ .reduce((results, item, index, arr) => {
996
+ if (index === 0) {
997
+ // Inner-most item
998
+ return `$expand=${item}`;
999
+ }
1000
+ else if (index === arr.length - 1) {
1001
+ // Outer-most item, don't add `$expand=` prefix (added above)
1002
+ return `${item}(${results})`;
1003
+ }
1004
+ else {
1005
+ // Other items
1006
+ return `$expand=${item}(${results})`;
1007
+ }
1008
+ }, '');
1731
1009
  }
1732
- /**
1733
- * Find an annotation inside the annotatable and return its value.
1734
- * @param term The term of the annotation to find.
1735
- * @returns The value of the annotation.
1736
- */
1737
- annotatedValue(term) {
1738
- const reg = term instanceof RegExp ? term : new RegExp(`^${term}$`);
1739
- const annot = this.findAnnotation((a) => reg.test(a.term));
1740
- if (!annot) {
1741
- return undefined;
1010
+ else if (Array.isArray(expands)) {
1011
+ return `${expands
1012
+ .map((e) => buildExpand(e, { aliases, escape }))
1013
+ .join(',')}`;
1014
+ }
1015
+ else if (typeof expands === 'object') {
1016
+ const expandKeys = Object.keys(expands);
1017
+ if (expandKeys.some((key) => SUPPORTED_EXPAND_PROPERTIES.indexOf(key.toLowerCase()) !== -1)) {
1018
+ return expandKeys
1019
+ .map((key) => {
1020
+ let value;
1021
+ switch (key) {
1022
+ case 'filter':
1023
+ value = buildFilter(expands[key], {
1024
+ aliases,
1025
+ escape,
1026
+ });
1027
+ break;
1028
+ case 'orderBy':
1029
+ value = buildOrderBy(expands[key]);
1030
+ break;
1031
+ case 'levels':
1032
+ case 'count':
1033
+ case 'top':
1034
+ case 'skip':
1035
+ value = `${expands[key]}`;
1036
+ if (isRawType(value))
1037
+ value = value.value;
1038
+ break;
1039
+ default:
1040
+ value = buildExpand(expands[key], { aliases, escape });
1041
+ }
1042
+ return `$${key.toLowerCase()}=${value}`;
1043
+ })
1044
+ .join(';');
1045
+ }
1046
+ else {
1047
+ return expandKeys
1048
+ .map((key) => {
1049
+ const builtExpand = buildExpand(expands[key], { aliases, escape });
1050
+ return builtExpand ? `${key}(${builtExpand})` : key;
1051
+ })
1052
+ .join(',');
1053
+ }
1054
+ }
1055
+ return '';
1056
+ }
1057
+ function buildTransforms(transforms, { aliases, escape = false, }) {
1058
+ // Wrap single object an array for simplified processing
1059
+ const transformsArray = Array.isArray(transforms) ? transforms : [transforms];
1060
+ const transformsResult = transformsArray.reduce((result, transform) => {
1061
+ const { aggregate, filter, groupBy, ...rest } = transform;
1062
+ // TODO: support as many of the following:
1063
+ // topcount, topsum, toppercent,
1064
+ // bottomsum, bottomcount, bottompercent,
1065
+ // identity, concat, expand, search, compute, isdefined
1066
+ const unsupportedKeys = Object.keys(rest);
1067
+ if (unsupportedKeys.length) {
1068
+ throw new Error(`Unsupported transform(s): ${unsupportedKeys}`);
1069
+ }
1070
+ if (aggregate) {
1071
+ result.push(`aggregate(${buildAggregate(aggregate)})`);
1072
+ }
1073
+ if (filter) {
1074
+ const builtFilter = buildFilter(filter, { aliases, escape });
1075
+ if (builtFilter) {
1076
+ result.push(`filter(${buildFilter(builtFilter, { aliases, escape })})`);
1077
+ }
1742
1078
  }
1743
- return (annot.string ||
1744
- annot.bool ||
1745
- annot.int ||
1746
- annot.permissions ||
1747
- annot.properties);
1748
- }
1079
+ if (groupBy) {
1080
+ result.push(`groupby(${buildGroupBy(groupBy, { aliases, escape })})`);
1081
+ }
1082
+ return result;
1083
+ }, []);
1084
+ return transformsResult.join('/') || undefined;
1749
1085
  }
1750
-
1751
- class ODataSchemaElement extends ODataAnnotatable {
1752
- name;
1753
- schema;
1754
- constructor(config, schema) {
1755
- super(config);
1756
- this.schema = schema;
1757
- this.name = config.name;
1758
- }
1759
- get api() {
1760
- return this.schema.api;
1761
- }
1762
- /**
1763
- * Create a nicer looking title.
1764
- * Titleize is meant for creating pretty output.
1765
- * @param term The term of the annotation to find.
1766
- * @returns The titleized string.
1767
- */
1768
- titleize(term) {
1769
- return (term && this.annotatedValue(term)) ?? Strings.titleCase(this.name);
1086
+ function buildAggregate(aggregate) {
1087
+ // Wrap single object in an array for simplified processing
1088
+ const aggregateArray = Array.isArray(aggregate) ? aggregate : [aggregate];
1089
+ return aggregateArray
1090
+ .map((aggregateItem) => {
1091
+ return typeof aggregateItem === 'string'
1092
+ ? aggregateItem
1093
+ : Object.keys(aggregateItem).map((aggregateKey) => {
1094
+ const aggregateValue = aggregateItem[aggregateKey];
1095
+ // TODO: Are these always required? Can/should we default them if so?
1096
+ if (!aggregateValue.with) {
1097
+ throw new Error(`'with' property required for '${aggregateKey}'`);
1098
+ }
1099
+ if (!aggregateValue.as) {
1100
+ throw new Error(`'as' property required for '${aggregateKey}'`);
1101
+ }
1102
+ return `${aggregateKey} with ${aggregateValue.with} as ${aggregateValue.as}`;
1103
+ });
1104
+ })
1105
+ .join(',');
1106
+ }
1107
+ function buildGroupBy(groupBy, { aliases, escape = false, }) {
1108
+ if (!groupBy.properties) {
1109
+ throw new Error(`'properties' property required for groupBy`);
1770
1110
  }
1771
- /**
1772
- * Returns a full type of the structured type including the namespace/alias.
1773
- * @param alias Use the alias of the namespace instead of the namespace.
1774
- * @returns The string representation of the type.
1775
- */
1776
- type({ alias = false } = {}) {
1777
- return `${alias ? this.schema.alias : this.schema.namespace}.${this.name}`;
1111
+ let result = `(${groupBy.properties.join(',')})`;
1112
+ if (groupBy.transform) {
1113
+ result += `,${buildTransforms(groupBy.transform, { aliases, escape })}`;
1778
1114
  }
1779
- /**
1780
- * Returns a boolean indicating if the structured type is of the given type.
1781
- * @param type String representation of the type
1782
- * @returns True if the callable is type of the given type
1783
- */
1784
- isTypeOf(element) {
1785
- const names = [`${this.schema.namespace}.${this.name}`];
1786
- if (this.schema.alias)
1787
- names.push(`${this.schema.alias}.${this.name}`);
1788
- return names.includes(element.type());
1115
+ return result;
1116
+ }
1117
+ function buildOrderBy(orderBy, prefix = '') {
1118
+ if (isRawType(orderBy)) {
1119
+ return orderBy.value;
1789
1120
  }
1790
- /**
1791
- * Returns a boolean indicating if the structured type is a subtype of the given type.
1792
- * @param type String representation of the type
1793
- * @returns True if the callable is type of the given type
1794
- */
1795
- isSubtypeOf(element) {
1796
- if (this.isTypeOf(element))
1797
- return true;
1798
- return false;
1121
+ else if (Array.isArray(orderBy)) {
1122
+ return orderBy
1123
+ .map((value) => Array.isArray(value) &&
1124
+ value.length === 2 &&
1125
+ ['asc', 'desc'].indexOf(value[1]) !== -1
1126
+ ? value.join(' ')
1127
+ : value)
1128
+ .map((v) => `${prefix}${v}`)
1129
+ .join(',');
1799
1130
  }
1800
- /**
1801
- * Returns a boolean indicating if the structured type is a supertype of the given type.
1802
- * @param type String representation of the type
1803
- * @returns True if the callable is type of the given type
1804
- */
1805
- isSupertypeOf(element) {
1806
- if (this.isTypeOf(element))
1807
- return true;
1808
- return false;
1131
+ else if (typeof orderBy === 'object') {
1132
+ return Object.entries(orderBy)
1133
+ .map(([k, v]) => buildOrderBy(v, `${k}/`))
1134
+ .map((v) => `${prefix}${v}`)
1135
+ .join(',');
1809
1136
  }
1137
+ return `${prefix}${orderBy}`;
1810
1138
  }
1811
- class ODataParserSchemaElement extends ODataSchemaElement {
1812
- parser;
1813
- constructor(config, schema, parser) {
1814
- super(config, schema);
1815
- this.parser = parser;
1816
- }
1139
+ function buildApply(apply, { aliases, escape = false, }) {
1140
+ const applyArray = Array.isArray(apply) ? apply : [apply];
1141
+ return applyArray
1142
+ .map((v) => normalizeValue(v, { aliases, escape }))
1143
+ .join('/');
1817
1144
  }
1818
-
1819
- //https://github.com/niklasvh/base64-arraybuffer
1820
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
1821
- // Use a lookup table to find the index.
1822
- const lookup = new Uint8Array(256);
1823
- for (var i = 0; i < chars.length; i++) {
1824
- lookup[chars.charCodeAt(i)] = i;
1145
+ function buildUrl(path, params) {
1146
+ // This can be refactored using URL API. But IE does not support it.
1147
+ const queries = Object.entries(params).map(([key, value]) => `${key}=${value}`);
1148
+ return queries.length ? `${path}?${queries.join('&')}` : path;
1825
1149
  }
1826
- const ArrayBuffers = {
1827
- toArrayBuffer(v) {
1828
- var bufferLength = v.length * 0.75, len = v.length, i, p = 0, encoded1, encoded2, encoded3, encoded4;
1829
- if (v[v.length - 1] === '=') {
1830
- bufferLength--;
1831
- if (v[v.length - 2] === '=') {
1832
- bufferLength--;
1833
- }
1150
+ function parseNot(builtFilters) {
1151
+ return `not (${builtFilters.join(' and ')})`;
1152
+ }
1153
+
1154
+ const ISO_REGEX = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
1155
+ const Dates = {
1156
+ isoStringToDate(value) {
1157
+ if (typeof value === 'string' && value.search(ISO_REGEX) === 0) {
1158
+ return new Date(value);
1834
1159
  }
1835
- var arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer);
1836
- for (i = 0; i < len; i += 4) {
1837
- encoded1 = lookup[v.charCodeAt(i)];
1838
- encoded2 = lookup[v.charCodeAt(i + 1)];
1839
- encoded3 = lookup[v.charCodeAt(i + 2)];
1840
- encoded4 = lookup[v.charCodeAt(i + 3)];
1841
- bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
1842
- bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
1843
- bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
1160
+ else if (Array.isArray(value)) {
1161
+ return value.map((v) => this.isoStringToDate(v));
1162
+ }
1163
+ else if (value && value.constructor === Object) {
1164
+ return Object.keys(value)
1165
+ .map((key) => [key, this.isoStringToDate(value[key])])
1166
+ .reduce((acc, v) => Object.assign(acc, { [v[0]]: v[1] }), {});
1167
+ }
1168
+ return value;
1169
+ },
1170
+ };
1171
+
1172
+ const DURATION_REGEX = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
1173
+ const Durations = {
1174
+ toDuration(v) {
1175
+ const matches = DURATION_REGEX.exec(v);
1176
+ if (!matches || v.length < 3) {
1177
+ throw new TypeError(`duration invalid: "${v}". Must be a ISO 8601 duration. See https://en.wikipedia.org/wiki/ISO_8601#Durations`);
1178
+ }
1179
+ let duration = {};
1180
+ duration.sign = matches[1] === '-' ? -1 : 1;
1181
+ return [
1182
+ 'years',
1183
+ 'months',
1184
+ 'weeks',
1185
+ 'days',
1186
+ 'hours',
1187
+ 'minutes',
1188
+ 'seconds',
1189
+ ].reduce((acc, name, index) => {
1190
+ const v = parseFloat(matches[index + 2]);
1191
+ if (!Number.isNaN(v))
1192
+ acc[name] = v;
1193
+ return acc;
1194
+ }, duration);
1195
+ },
1196
+ toString(v) {
1197
+ return [
1198
+ v.sign === -1 ? '-' : '',
1199
+ 'P',
1200
+ v.years ? v.years + 'Y' : '',
1201
+ v.months ? v.months + 'M' : '',
1202
+ v.weeks ? v.weeks + 'W' : '',
1203
+ v.days ? v.days + 'D' : '',
1204
+ 'T',
1205
+ v.hours ? v.hours + 'H' : '',
1206
+ v.minutes ? v.minutes + 'M' : '',
1207
+ v.seconds ? v.seconds + 'S' : '',
1208
+ ].join('');
1209
+ },
1210
+ };
1211
+
1212
+ const Enums = {
1213
+ names(enums) {
1214
+ return Object.values(enums).filter((v) => typeof v === 'string');
1215
+ },
1216
+ values(enums) {
1217
+ return Object.values(enums).filter((v) => typeof v === 'number');
1218
+ },
1219
+ toValue(enums, value) {
1220
+ if (value in enums)
1221
+ return typeof value === 'string' ? enums[value] : value;
1222
+ return undefined;
1223
+ },
1224
+ toValues(enums, value) {
1225
+ if (typeof value === 'number') {
1226
+ return this.values(enums).filter((v) => (value & v) === v);
1227
+ }
1228
+ if (typeof value === 'string') {
1229
+ value = value.split(',').map((o) => o.trim());
1230
+ }
1231
+ if (Array.isArray(value) && value.every((v) => v in enums)) {
1232
+ return value.map((o) => this.toValue(enums, o));
1233
+ }
1234
+ return [];
1235
+ },
1236
+ toName(enums, value) {
1237
+ if (value in enums)
1238
+ return typeof value === 'number' ? enums[value] : value;
1239
+ return undefined;
1240
+ },
1241
+ toNames(enums, value) {
1242
+ if (typeof value === 'number') {
1243
+ return this.values(enums)
1244
+ .filter((v) => (value & v) === v)
1245
+ .map((v) => this.toName(enums, v));
1246
+ }
1247
+ if (typeof value === 'string') {
1248
+ value = value.split(',').map((o) => o.trim());
1249
+ }
1250
+ if (Array.isArray(value) && value.every((v) => v in enums)) {
1251
+ return value.map((o) => this.toName(enums, o));
1844
1252
  }
1845
- return arraybuffer;
1253
+ return [];
1846
1254
  },
1847
- toString(v) {
1848
- var bytes = new Uint8Array(v), i, len = bytes.length, base64 = '';
1849
- for (i = 0; i < len; i += 3) {
1850
- base64 += chars[bytes[i] >> 2];
1851
- base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
1852
- base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
1853
- base64 += chars[bytes[i + 2] & 63];
1255
+ toFlags(enums, value) {
1256
+ if (typeof value === 'number') {
1257
+ return this.values(enums)
1258
+ .filter((v) => v !== 0 && (value & v) === v)
1259
+ .map((v) => this.toName(enums, v));
1854
1260
  }
1855
- if (len % 3 === 2) {
1856
- base64 = base64.substring(0, base64.length - 1) + '=';
1261
+ if (typeof value === 'string') {
1262
+ value = value.split(',').map((o) => o.trim());
1857
1263
  }
1858
- else if (len % 3 === 1) {
1859
- base64 = base64.substring(0, base64.length - 2) + '==';
1264
+ if (Array.isArray(value) && value.every((v) => v in enums)) {
1265
+ return value
1266
+ .filter((v) => enums[v])
1267
+ .map((v) => this.toName(enums, v));
1860
1268
  }
1861
- return base64;
1269
+ return [];
1862
1270
  },
1863
1271
  };
1864
1272
 
1865
- // Core EdmTypeParserBuilder
1866
- const EdmParser = (_d, _s, _e) => ({
1867
- deserialize(value, options) {
1868
- return Array.isArray(value)
1869
- ? value.map((v) => _d(v, options))
1870
- : _d(value, options);
1871
- },
1872
- serialize(value, options) {
1873
- return Array.isArray(value)
1874
- ? value.map((v) => _s(v, options))
1875
- : _s(value, options);
1273
+ function cloneSymbol(targe) {
1274
+ return Object(Symbol.prototype.valueOf.call(targe));
1275
+ }
1276
+ function cloneReg(targe) {
1277
+ const reFlags = /\w*$/;
1278
+ const result = new targe.constructor(targe.source, reFlags.exec(targe));
1279
+ result.lastIndex = targe.lastIndex;
1280
+ return result;
1281
+ }
1282
+ const Types = {
1283
+ rawType(value) {
1284
+ return Object.prototype.toString.call(value).slice(8, -1);
1876
1285
  },
1877
- encode(value, options) {
1878
- return Array.isArray(value)
1879
- ? value.map((v) => (!isRawType(v) ? _e(v, options) : v))
1880
- : !isRawType(value)
1881
- ? _e(value, options)
1882
- : value;
1286
+ isObject(value) {
1287
+ return typeof value === 'object' && value !== null;
1883
1288
  },
1884
- });
1885
- const Identity = (v) => v;
1886
- const toNumber = (v) => Number(v);
1887
- const toString = (v) => v.toString();
1888
- const toBoolean = (v) => Boolean(v);
1889
- const toDate = (v) => new Date(v);
1890
- const EDM_PARSERS = {
1891
- //Edm.Guid 16-byte (128-bit) unique identifier
1892
- [EdmType.Guid]: EdmParser(Identity, Identity, (v) => raw(v)),
1893
- //Edm.Int16 Signed 16-bit integer
1894
- [EdmType.Int16]: EdmParser(toNumber, toNumber, toNumber),
1895
- //Edm.String Sequence of UTF-8 characters
1896
- [EdmType.String]: EdmParser(toString, toString, toString),
1897
- //Edm.Boolean Binary-valued logic
1898
- [EdmType.Boolean]: EdmParser(toBoolean, toBoolean, toBoolean),
1899
- //Edm.Byte Unsigned 8-bit integer
1900
- [EdmType.Byte]: EdmParser(toNumber, toNumber, toNumber),
1901
- //Edm.SByte Signed 8-bit integer
1902
- [EdmType.SByte]: EdmParser(toNumber, toNumber, toNumber),
1903
- //Edm.Int32 Signed 16-bit integer
1904
- [EdmType.Int32]: EdmParser(toNumber, toNumber, toNumber),
1905
- //Edm.Int64 Signed 16-bit integer
1906
- [EdmType.Int64]: EdmParser(toNumber, toNumber, toNumber),
1907
- //Edm.Date Date without a time-zone offset
1908
- [EdmType.Date]: EdmParser((v) => new Date(`${v}T00:00:00.000Z`), (v) => toDate(v).toISOString().substring(0, 10), (v) => raw(toDate(v).toISOString().substring(0, 10))),
1909
- //Edm.TimeOfDay Clock time 00:00-23:59:59.999999999999
1910
- [EdmType.TimeOfDay]: EdmParser((v) => new Date(`1970-01-01T${v}Z`), (v) => toDate(v).toISOString().substring(11, 23), (v) => raw(toDate(v).toISOString().substring(11, 23))),
1911
- //Edm.DateTimeOffset Date and time with a time-zone offset, no leap seconds
1912
- [EdmType.DateTimeOffset]: EdmParser(toDate, (v) => toDate(v).toISOString(), (v) => raw(toDate(v).toISOString())),
1913
- //Edm.Duration Signed duration in days, hours, minutes, and (sub)seconds
1914
- [EdmType.Duration]: EdmParser((v) => Durations.toDuration(v), (v) => Durations.toString(v), (v) => raw(Durations.toString(v))),
1915
- //Edm.Decimal Numeric values with fixed precision and scale
1916
- [EdmType.Decimal]: EdmParser(toNumber, (v, o) => {
1917
- if (o.ieee754Compatible) {
1918
- let vstr = v.toPrecision(o.field.precision);
1919
- if (typeof o.field.scale === 'number') {
1920
- vstr = parseFloat(vstr).toFixed(o.field.scale);
1921
- }
1922
- return vstr;
1923
- }
1924
- return v;
1925
- }, (v, o) => {
1926
- if (o.ieee754Compatible) {
1927
- let vstr = v.toPrecision(o.field.precision);
1928
- if (typeof o.field.scale === 'number') {
1929
- vstr = parseFloat(vstr).toFixed(o.field.scale);
1930
- }
1931
- return raw(vstr);
1289
+ isPlainObject(value) {
1290
+ if (this.rawType(value) !== 'Object') {
1291
+ return false;
1932
1292
  }
1933
- return v;
1934
- }),
1935
- //Edm.Double IEEE 754 binary64 floating-point number (15-17 decimal digits)
1936
- [EdmType.Double]: EdmParser((v) => (v === 'INF' ? Infinity : v), (v) => (v === Infinity ? 'INF' : v), (v) => raw(v === Infinity ? 'INF' : v.toString())),
1937
- //Edm.Single IEEE 754 binary32 floating-point number (6-9 decimal digits)
1938
- [EdmType.Single]: EdmParser((v) => (v === 'INF' ? Infinity : v), (v) => (v === Infinity ? 'INF' : v), (v) => raw(v === Infinity ? 'INF' : v.toString())),
1939
- //Edm.Binary Binary data
1940
- [EdmType.Binary]: EdmParser((v) => ArrayBuffers.toArrayBuffer(v), (v) => ArrayBuffers.toString(v), (v) => raw(ArrayBuffers.toString(v))),
1941
- };
1942
- /*
1943
- Edm.Stream Binary data stream
1944
- Edm.Geography Abstract base type for all Geography types
1945
- Edm.GeographyPoint A point in a round-earth coordinate system
1946
- Edm.GeographyLineString Line string in a round-earth coordinate system
1947
- Edm.GeographyPolygon Polygon in a round-earth coordinate system
1948
- Edm.GeographyMultiPoint Collection of points in a round-earth coordinate system
1949
- Edm.GeographyMultiLineString Collection of line strings in a round-earth coordinate system
1950
- Edm.GeographyMultiPolygon Collection of polygons in a round-earth coordinate system
1951
- Edm.GeographyCollection Collection of arbitrary Geography values
1952
- Edm.Geometry Abstract base type for all Geometry types
1953
- Edm.GeometryPoint Point in a flat-earth coordinate system
1954
- Edm.GeometryLineString Line string in a flat-earth coordinate system
1955
- Edm.GeometryPolygon Polygon in a flat-earth coordinate system
1956
- Edm.GeometryMultiPoint Collection of points in a flat-earth coordinate system
1957
- Edm.GeometryMultiLineString Collection of line strings in a flat-earth coordinate system
1958
- Edm.GeometryMultiPolygon Collection of polygons in a flat-earth coordinate system
1959
- Edm.GeometryCollection Collection of arbitrary Geometry values
1960
- */
1961
-
1962
- class ODataEnumTypeFieldParser extends ODataAnnotatable {
1963
- name;
1964
- value;
1965
- constructor(name, field) {
1966
- super(field);
1967
- this.name = name;
1968
- this.value = field.value;
1969
- }
1970
- titleize(term) {
1971
- return (term && this.annotatedValue(term)) || this.name;
1972
- }
1973
- }
1974
- class ODataEnumTypeParser extends ODataAnnotatable {
1975
- name;
1976
- namespace;
1977
- alias;
1978
- flags;
1979
- members;
1980
- _fields;
1981
- parserOptions;
1982
- constructor(config, namespace, alias) {
1983
- super(config);
1984
- this.name = config.name;
1985
- this.namespace = namespace;
1986
- this.alias = alias;
1987
- this.flags = config.flags;
1988
- this.members = config.members;
1989
- this._fields = Object.entries(config.fields).map(([name, f]) => new ODataEnumTypeFieldParser(name, f));
1990
- }
1991
- configure({ options }) {
1992
- this.parserOptions = options;
1993
- }
1994
- isTypeOf(type) {
1995
- var names = [`${this.namespace}.${this.name}`];
1996
- if (this.alias)
1997
- names.push(`${this.alias}.${this.name}`);
1998
- return names.indexOf(type) !== -1;
1999
- }
2000
- fields(namesValue) {
2001
- if (namesValue === undefined)
2002
- return [...this._fields];
2003
- if (Array.isArray(namesValue))
2004
- return [...this._fields.filter((f) => namesValue.includes(f.value))];
2005
- if (typeof namesValue === 'number') {
2006
- return [
2007
- ...this._fields.filter((f) => (this.flags && Boolean(f.value & namesValue)) ||
2008
- f.value === namesValue),
2009
- ];
1293
+ const prototype = Object.getPrototypeOf(value);
1294
+ return prototype === null || prototype === Object.prototype;
1295
+ },
1296
+ isFunction(value) {
1297
+ return typeof value === 'function';
1298
+ },
1299
+ isArray(value) {
1300
+ return Array.isArray(value);
1301
+ },
1302
+ isMap(value) {
1303
+ return this.rawType(value) === 'Map';
1304
+ },
1305
+ isEmpty(value) {
1306
+ return (value === undefined ||
1307
+ value === null ||
1308
+ (typeof value === 'string' && !value.length) ||
1309
+ (value instanceof Date && isNaN(value.valueOf())) ||
1310
+ (Types.isMap(value) && !value.size) ||
1311
+ (Types.isArray(value) && !value.length) ||
1312
+ (Types.isFunction(value.isEmpty) && value.isEmpty()) ||
1313
+ (Types.isArray(value) &&
1314
+ value.every((v) => Types.isEmpty(v))) ||
1315
+ (Types.isPlainObject(value) &&
1316
+ !Object.keys(value).filter((k) => value.hasOwnProperty(k)).length));
1317
+ },
1318
+ isEqual(value1, value2) {
1319
+ function getType(obj) {
1320
+ return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
2010
1321
  }
2011
- if (typeof namesValue === 'string') {
2012
- const names = namesValue.split(',').map((o) => o.trim());
2013
- return this._fields.filter((f) => names.includes(f.name));
1322
+ function areDatesEqual() {
1323
+ return value1.getTime() === value2.getTime();
2014
1324
  }
2015
- return [];
2016
- }
2017
- field(nameValue) {
2018
- const field = this.fields().find((f) => f.name === nameValue || f.value === nameValue);
2019
- //Throw error if not found
2020
- //if (field === undefined)
2021
- // throw new Error(`${this.name} has no field for ${nameValue}`);
2022
- return field;
2023
- }
2024
- /**
2025
- * Map the fields of the enum type.
2026
- * @param mapper Function that maps the value to the new value
2027
- * @returns The fields mapped by the mapper
2028
- */
2029
- mapFields(mapper) {
2030
- return this.fields().map(mapper);
2031
- }
2032
- // Deserialize
2033
- deserialize(value, options) {
2034
- // string -> number
2035
- const parserOptions = { ...this.parserOptions, ...options };
2036
- if (this.flags) {
2037
- return this.fields(value).reduce((acc, f) => acc | f.value, 0);
1325
+ function areArraysBufferEqual() {
1326
+ if (value1.byteLength !== value2.byteLength) {
1327
+ return false;
1328
+ }
1329
+ var view1 = new DataView(value1);
1330
+ var view2 = new DataView(value2);
1331
+ var i = value1.byteLength;
1332
+ while (i--) {
1333
+ if (view1.getUint8(i) !== view2.getUint8(i)) {
1334
+ return false;
1335
+ }
1336
+ }
1337
+ return true;
2038
1338
  }
2039
- else {
2040
- return this.field(value)?.value;
1339
+ function areArraysEqual() {
1340
+ // Check length
1341
+ if (value1.length !== value2.length)
1342
+ return false;
1343
+ // Check each item in the array
1344
+ for (let i = 0; i < value1.length; i++) {
1345
+ if (!Types.isEqual(value1[i], value2[i]))
1346
+ return false;
1347
+ }
1348
+ // If no errors, return true
1349
+ return true;
2041
1350
  }
2042
- }
2043
- // Serialize
2044
- serialize(value, options) {
2045
- // Enum are string | number
2046
- // string | number -> string
2047
- const parserOptions = { ...this.parserOptions, ...options };
2048
- if (this.flags) {
2049
- let names = this.fields(value).map((f) => f.name);
2050
- if (names.length === 0)
2051
- names = [`${value}`];
2052
- return !parserOptions?.stringAsEnum
2053
- ? `${this.namespace}.${this.name}'${names.join(', ')}'`
2054
- : names.join(', ');
1351
+ function areObjectsEqual() {
1352
+ if (Object.keys(value1).length !== Object.keys(value2).length)
1353
+ return false;
1354
+ // Check each item in the object
1355
+ for (let key in value1) {
1356
+ if (Object.prototype.hasOwnProperty.call(value1, key)) {
1357
+ if (!Types.isEqual(value1[key], value2[key]))
1358
+ return false;
1359
+ }
1360
+ }
1361
+ // If no errors, return true
1362
+ return true;
2055
1363
  }
2056
- else {
2057
- let name = this.field(value)?.name;
2058
- if (name === undefined)
2059
- name = `${value}`;
2060
- return !parserOptions?.stringAsEnum
2061
- ? `${this.namespace}.${this.name}'${name}'`
2062
- : name;
1364
+ function areFunctionsEqual() {
1365
+ return value1.toString() === value2.toString();
2063
1366
  }
2064
- }
2065
- //Encode
2066
- encode(value, options) {
2067
- const parserOptions = { ...this.parserOptions, ...options };
2068
- const serialized = this.serialize(value, parserOptions);
2069
- if (serialized === undefined)
2070
- return undefined;
2071
- return parserOptions?.stringAsEnum
2072
- ? raw(`'${serialized}'`)
2073
- : raw(serialized);
2074
- }
2075
- // Json Schema
2076
- toJsonSchema() {
2077
- return this.flags
2078
- ? {
2079
- title: this.name,
2080
- type: JsonType.array,
2081
- items: {
2082
- type: JsonType.integer,
2083
- },
2084
- }
2085
- : {
2086
- type: JsonType.integer,
2087
- enum: this._fields.map((f) => f.value),
2088
- };
2089
- }
2090
- validate(value, { method, navigation = false, } = {}) {
2091
- if (this.flags) {
2092
- let fields = this.fields(value);
2093
- return value && fields.length === 0 ? ['mismatch'] : undefined;
1367
+ function arePrimativesEqual() {
1368
+ return value1 === value2;
2094
1369
  }
2095
- else {
2096
- return this.fields(value).length !== 1 ? ['mismatch'] : undefined;
1370
+ // Get the object type
1371
+ let type = getType(value1);
1372
+ // If the two items are not the same type, return false
1373
+ if (type !== getType(value2))
1374
+ return false;
1375
+ // Compare based on type
1376
+ if (type === 'date')
1377
+ return areDatesEqual();
1378
+ if (type === 'arraybuffer')
1379
+ return areArraysBufferEqual();
1380
+ if (type === 'array')
1381
+ return areArraysEqual();
1382
+ if (type === 'object')
1383
+ return areObjectsEqual();
1384
+ if (type === 'function')
1385
+ return areFunctionsEqual();
1386
+ return arePrimativesEqual();
1387
+ },
1388
+ clone(target) {
1389
+ const constrFun = target.constructor;
1390
+ switch (this.rawType(target)) {
1391
+ case 'Boolean':
1392
+ case 'Number':
1393
+ case 'String':
1394
+ case 'Error':
1395
+ case 'Date':
1396
+ return new constrFun(target);
1397
+ case 'RegExp':
1398
+ return cloneReg(target);
1399
+ case 'Symbol':
1400
+ return cloneSymbol(target);
1401
+ case 'Function':
1402
+ return target;
1403
+ default:
1404
+ return null;
2097
1405
  }
2098
- }
2099
- unpack(value) {
2100
- return this.fields(value).map((f) => f.value);
2101
- }
2102
- pack(value) {
2103
- return this.fields(value).reduce((acc, v) => acc | v.value, 0);
2104
- }
2105
- }
1406
+ },
1407
+ };
2106
1408
 
2107
- const COLLECTION = /Collection\(([\w\.]+)\)/;
2108
- const PROPERTY = /([\w\d\-_]+)\(([\'\w\d\-_=]+)\)/;
2109
- const EXPAND = /([\w\d\-_]+)\(([\w\d\,\(\)]+)\)/;
2110
- const ODataVersionBaseHelper = {
2111
- entity(data) {
2112
- return data;
1409
+ const Http = {
1410
+ //Merge Headers
1411
+ mergeHttpHeaders(...values) {
1412
+ let headers = new HttpHeaders();
1413
+ values.forEach((value) => {
1414
+ if (value instanceof HttpHeaders) {
1415
+ value.keys().forEach((key) => {
1416
+ headers = (value.getAll(key) || []).reduce((acc, v) => acc.append(key, v), headers);
1417
+ });
1418
+ }
1419
+ else if (Types.isPlainObject(value)) {
1420
+ Object.entries(value).forEach(([key, value]) => {
1421
+ headers = (Array.isArray(value) ? value : [value]).reduce((acc, v) => acc.append(key, v), headers);
1422
+ });
1423
+ }
1424
+ });
1425
+ return headers;
2113
1426
  },
2114
- entities(data) {
2115
- return data[this.VALUE];
1427
+ // Merge Params
1428
+ mergeHttpParams(...values) {
1429
+ let params = new HttpParams();
1430
+ values.forEach((value) => {
1431
+ if (value instanceof HttpParams) {
1432
+ value.keys().forEach((key) => {
1433
+ params = (value.getAll(key) || []).reduce((acc, v) => acc.append(key, v), params);
1434
+ });
1435
+ }
1436
+ else if (Types.isPlainObject(value)) {
1437
+ Object.entries(value).forEach(([key, value]) => {
1438
+ params = (Array.isArray(value) ? value : [value]).reduce((acc, v) => acc.append(key, v), params);
1439
+ });
1440
+ }
1441
+ });
1442
+ return params;
2116
1443
  },
2117
- property(data) {
2118
- return this.VALUE in data ? data[this.VALUE] : data;
1444
+ // Split Params
1445
+ splitHttpParams(params, keys) {
1446
+ let other = new HttpParams();
1447
+ params.keys().forEach((key) => {
1448
+ if (keys.includes(key)) {
1449
+ other = (params.getAll(key) || []).reduce((acc, v) => acc.append(key, v), other);
1450
+ params = params.delete(key);
1451
+ }
1452
+ });
1453
+ return [params, other];
2119
1454
  },
2120
- functions(annots) {
2121
- const funcs = new Map();
2122
- [...annots.keys()]
2123
- .filter((key) => key.startsWith(this.ODATA_FUNCTION_PREFIX))
2124
- .forEach((key) => funcs.set(key.substring(this.ODATA_FUNCTION_PREFIX.length), annots.get(key)));
2125
- return funcs;
1455
+ // Without Params
1456
+ withoutHttpParams(params, keys) {
1457
+ return keys.reduce((acc, key) => acc.delete(key), params);
2126
1458
  },
2127
- properties(annots) {
2128
- const props = new Map();
2129
- [...annots.keys()]
2130
- .filter((key) => key.indexOf(this.ODATA_ANNOTATION_PREFIX) > 0)
2131
- .forEach((key) => {
2132
- let name = key.substring(0, key.indexOf(this.ODATA_ANNOTATION_PREFIX));
2133
- let prop = props.has(name) ? props.get(name) : new Map();
2134
- prop.set(key.substring(key.indexOf(this.ODATA_ANNOTATION_PREFIX)), annots.get(key));
2135
- props.set(name, prop);
2136
- });
2137
- return props;
1459
+ resolveHeaderKey(headers, options) {
1460
+ if (headers instanceof HttpHeaders) {
1461
+ return headers.keys().find((k) => options.indexOf(k) !== -1);
1462
+ }
1463
+ else if (Types.isPlainObject(headers)) {
1464
+ return Object.keys(headers).find((k) => options.indexOf(k) !== -1);
1465
+ }
1466
+ return undefined;
2138
1467
  },
2139
- id(annots) {
2140
- return annots instanceof Map
2141
- ? annots.get(this.ODATA_ID)
2142
- : annots[this.ODATA_ID];
1468
+ headerValue(header) {
1469
+ let res = header.split(';')[0].trim();
1470
+ res = res.split(':')[1].trim();
1471
+ return res;
2143
1472
  },
2144
- etag(annots) {
2145
- return annots instanceof Map
2146
- ? annots.get(this.ODATA_ETAG)
2147
- : annots[this.ODATA_ETAG];
1473
+ parseResponseStatus(line) {
1474
+ const chunks = line.split(' ');
1475
+ return {
1476
+ status: chunks[0],
1477
+ code: parseInt(chunks[1], 10),
1478
+ message: chunks.slice(2).join(' '),
1479
+ };
2148
1480
  },
2149
- type(annots) {
2150
- let type = annots instanceof Map
2151
- ? annots.get(this.ODATA_TYPE)
2152
- : annots[this.ODATA_TYPE];
2153
- if (!type)
2154
- return undefined;
2155
- type = type.substring(1);
2156
- const matches = COLLECTION.exec(type);
2157
- if (matches)
2158
- return matches[1].indexOf('.') === -1 ? `Edm.${matches[1]}` : matches[1];
2159
- return type;
1481
+ boundaryDelimiter(contentType) {
1482
+ const contentTypeParts = contentType.split(';');
1483
+ if (contentTypeParts.length === 2) {
1484
+ const boundary = contentType.split(';')[1].trim();
1485
+ const boundaryDelimiter = BOUNDARY_PREFIX_SUFFIX + boundary.split('=')[1];
1486
+ return boundaryDelimiter;
1487
+ }
1488
+ else {
1489
+ return '';
1490
+ }
1491
+ },
1492
+ boundaryEnd(boundaryDelimiter) {
1493
+ if (!boundaryDelimiter.length) {
1494
+ return '';
1495
+ }
1496
+ const boundaryEnd = boundaryDelimiter + BOUNDARY_PREFIX_SUFFIX;
1497
+ return boundaryEnd;
1498
+ },
1499
+ };
1500
+
1501
+ function forEach(array, iteratee) {
1502
+ let index = -1;
1503
+ const length = array.length;
1504
+ while (++index < length) {
1505
+ iteratee(array[index], index);
1506
+ }
1507
+ return array;
1508
+ }
1509
+ const Objects = {
1510
+ set(obj, path, value) {
1511
+ // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1512
+ const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1513
+ pathArray.reduce((acc, key, i) => {
1514
+ if (acc[key] === undefined)
1515
+ acc[key] = {};
1516
+ if (i === pathArray.length - 1)
1517
+ acc[key] = value;
1518
+ return acc[key];
1519
+ }, obj);
2160
1520
  },
2161
- mediaEtag(annots) {
2162
- return annots.has(this.ODATA_MEDIA_ETAG)
2163
- ? decodeURIComponent(annots.get(this.ODATA_MEDIA_ETAG))
2164
- : undefined;
1521
+ get(obj, path, def) {
1522
+ // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1523
+ const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1524
+ // Find value if exist return otherwise return undefined value;
1525
+ return (pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj) || def);
2165
1526
  },
2166
- metadataEtag(annots) {
2167
- return annots.has(this.ODATA_METADATA_ETAG)
2168
- ? decodeURIComponent(annots.get(this.ODATA_METADATA_ETAG))
2169
- : undefined;
1527
+ unset(obj, path) {
1528
+ // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1529
+ const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1530
+ pathArray.reduce((acc, key, i) => {
1531
+ if (i === pathArray.length - 1)
1532
+ delete acc[key];
1533
+ return acc[key];
1534
+ }, obj);
2170
1535
  },
2171
- count(annots) {
2172
- return annots.has(this.ODATA_COUNT)
2173
- ? Number(annots.get(this.ODATA_COUNT))
2174
- : undefined;
1536
+ has(obj, path) {
1537
+ // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
1538
+ const pathArray = (Types.isArray(path) ? path : path.match(/([^[.\]])+/g));
1539
+ return !!pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
2175
1540
  },
2176
- annotations(value) {
2177
- const annots = new Map();
2178
- Object.entries(value)
2179
- .filter(([key]) => key.indexOf(this.ODATA_ANNOTATION_PREFIX) !== -1 ||
2180
- key.startsWith(this.ODATA_FUNCTION_PREFIX))
2181
- .forEach(([key, value]) => annots.set(key, value));
2182
- return annots;
1541
+ merge(target, source) {
1542
+ const merge = (target, source) => {
1543
+ for (let attr in source) {
1544
+ let value = source[attr];
1545
+ if (value !== null && Types.isPlainObject(value) && attr in target) {
1546
+ merge(target[attr], value);
1547
+ }
1548
+ else if (target[attr] !== value) {
1549
+ target[attr] = value;
1550
+ }
1551
+ }
1552
+ };
1553
+ merge(target, source);
1554
+ return target;
2183
1555
  },
2184
- attributes(value, metadata) {
2185
- return Object.entries(value)
2186
- .filter(([k]) => metadata === 'none' ||
2187
- (metadata === 'minimal' &&
2188
- (k.indexOf(this.ODATA_ANNOTATION_PREFIX) === -1 ||
2189
- k.startsWith(this.ODATA_ANNOTATION_PREFIX)) &&
2190
- !k.startsWith(this.ODATA_FUNCTION_PREFIX)) ||
2191
- (metadata === 'full' &&
2192
- k.indexOf(this.ODATA_ANNOTATION_PREFIX) === -1 &&
2193
- !k.startsWith(this.ODATA_FUNCTION_PREFIX)))
2194
- .reduce((acc, e) => ({ ...acc, [e[0]]: e[1] }), {});
1556
+ equal(object1, object2) {
1557
+ const keys1 = Object.keys(object1);
1558
+ const keys2 = Object.keys(object2);
1559
+ if (keys1.length !== keys2.length) {
1560
+ return false;
1561
+ }
1562
+ for (const key of keys1) {
1563
+ const val1 = object1[key];
1564
+ const val2 = object2[key];
1565
+ const areObjects = Types.isPlainObject(val1) && Types.isPlainObject(val2);
1566
+ if ((areObjects && !Objects.equal(val1, val2)) ||
1567
+ (!areObjects && val1 !== val2)) {
1568
+ return false;
1569
+ }
1570
+ }
1571
+ return true;
2195
1572
  },
2196
- nextLink(annots) {
2197
- return annots.has(this.ODATA_NEXTLINK)
2198
- ? decodeURIComponent(annots.get(this.ODATA_NEXTLINK))
2199
- : undefined;
1573
+ difference(object1, object2) {
1574
+ if (!object2 || !Types.isPlainObject(object2)) {
1575
+ return object1;
1576
+ }
1577
+ var diffs = {};
1578
+ var key;
1579
+ var arraysMatch = function (arr1, arr2) {
1580
+ if (arr1.length !== arr2.length)
1581
+ return false;
1582
+ for (var i = 0; i < arr1.length; i++) {
1583
+ if (arr1[i] !== arr2[i])
1584
+ return false;
1585
+ }
1586
+ return true;
1587
+ };
1588
+ var compare = function (item1, item2, key) {
1589
+ if (item2 === undefined) {
1590
+ diffs[key] = null;
1591
+ return;
1592
+ }
1593
+ if (typeof item1 !== typeof item2) {
1594
+ diffs[key] = item2;
1595
+ return;
1596
+ }
1597
+ if (Types.isPlainObject(item1)) {
1598
+ var objDiff = Objects.difference(item1, item2);
1599
+ if (Object.keys(objDiff).length > 0) {
1600
+ diffs[key] = objDiff;
1601
+ }
1602
+ return;
1603
+ }
1604
+ if (Array.isArray(item1)) {
1605
+ if (!arraysMatch(item1, item2)) {
1606
+ diffs[key] = item2;
1607
+ }
1608
+ return;
1609
+ }
1610
+ if (item1 !== item2) {
1611
+ diffs[key] = item2;
1612
+ }
1613
+ };
1614
+ for (key in object1) {
1615
+ if (object1.hasOwnProperty(key)) {
1616
+ compare(object1[key], object2[key], key);
1617
+ }
1618
+ }
1619
+ for (key in object2) {
1620
+ if (object2.hasOwnProperty(key)) {
1621
+ if (!object1[key] && object1[key] !== object2[key]) {
1622
+ diffs[key] = object2[key];
1623
+ }
1624
+ }
1625
+ }
1626
+ return diffs;
2200
1627
  },
2201
- readLink(annots) {
2202
- return annots.has(this.ODATA_READLINK)
2203
- ? decodeURIComponent(annots.get(this.ODATA_READLINK))
2204
- : undefined;
1628
+ resolveKey(key, { single = true } = {}) {
1629
+ const type = Types.rawType(key);
1630
+ if (['number', 'string'].indexOf(type) !== -1)
1631
+ return key;
1632
+ if (type !== 'Map' && type !== 'Object') {
1633
+ return undefined;
1634
+ }
1635
+ const values = type === 'Map' ? Array.from(key.values()) : Object.values(key);
1636
+ if (values.length === 1 && single) {
1637
+ // Single primitive key value
1638
+ key = values[0];
1639
+ return !Types.isEmpty(key) ? key : undefined;
1640
+ }
1641
+ else if (values.some((v) => v === undefined)) {
1642
+ // Compose key, needs all values
1643
+ return undefined;
1644
+ }
1645
+ else {
1646
+ const obj = type === 'Map' ? Object.fromEntries(key) : key;
1647
+ return !Types.isEmpty(obj) ? obj : undefined;
1648
+ }
2205
1649
  },
2206
- mediaReadLink(annots) {
2207
- return annots.has(this.ODATA_MEDIA_READLINK)
2208
- ? decodeURIComponent(annots.get(this.ODATA_MEDIA_READLINK))
2209
- : undefined;
1650
+ clone(target, map) {
1651
+ if (map === undefined)
1652
+ map = new WeakMap();
1653
+ // clone primitive types
1654
+ if (typeof target != 'object' || target == null) {
1655
+ return target;
1656
+ }
1657
+ if ('clone' in target) {
1658
+ // target is a cloneable object
1659
+ return target.clone();
1660
+ }
1661
+ const type = Types.rawType(target);
1662
+ let cloneTarget = null;
1663
+ if (map.get(target)) {
1664
+ return map.get(target);
1665
+ }
1666
+ map.set(target, cloneTarget);
1667
+ if (type != 'Set' && type != 'Map' && type != 'Array' && type != 'Object') {
1668
+ return Types.clone(target);
1669
+ }
1670
+ // clone Set
1671
+ if (type == 'Set') {
1672
+ cloneTarget = new Set();
1673
+ target.forEach((value) => {
1674
+ cloneTarget.add(this.clone(value, map));
1675
+ });
1676
+ return cloneTarget;
1677
+ }
1678
+ // clone Map
1679
+ if (type == 'Map') {
1680
+ cloneTarget = new Map();
1681
+ target.forEach((value, key) => {
1682
+ cloneTarget.set(key, this.clone(value, map));
1683
+ });
1684
+ return cloneTarget;
1685
+ }
1686
+ // clone Array
1687
+ if (type == 'Array') {
1688
+ cloneTarget = new Array();
1689
+ forEach(target, (value, index) => {
1690
+ cloneTarget[index] = this.clone(value, map);
1691
+ });
1692
+ }
1693
+ // clone normal Object
1694
+ if (type == 'Object') {
1695
+ cloneTarget = new Object();
1696
+ forEach(Object.keys(target), (key, index) => {
1697
+ cloneTarget[key] = this.clone(target[key], map);
1698
+ });
1699
+ }
1700
+ return cloneTarget;
2210
1701
  },
2211
- editLink(annots) {
2212
- return annots.has(this.ODATA_EDITLINK)
2213
- ? decodeURIComponent(annots.get(this.ODATA_EDITLINK))
2214
- : undefined;
1702
+ };
1703
+
1704
+ const OData = {
1705
+ // Merge callables parameters
1706
+ mergeCallableParameters(callables) {
1707
+ const areEqual = (a, b) => a.name === b.name &&
1708
+ Objects.equal((a.parameters || {})[CALLABLE_BINDING_PARAMETER] || {}, (b.parameters || {})[CALLABLE_BINDING_PARAMETER] || {});
1709
+ return callables.reduce((acc, config) => {
1710
+ if (acc.every((c) => !areEqual(c, config))) {
1711
+ config = callables
1712
+ .filter((c) => areEqual(c, config))
1713
+ .reduce((acc, c) => {
1714
+ acc.parameters = Object.assign(acc.parameters || {}, c.parameters || {});
1715
+ return acc;
1716
+ }, config);
1717
+ return [...acc, config];
1718
+ }
1719
+ return acc;
1720
+ }, []);
2215
1721
  },
2216
- mediaEditLink(annots) {
2217
- return annots.has(this.ODATA_MEDIA_EDITLINK)
2218
- ? decodeURIComponent(annots.get(this.ODATA_MEDIA_EDITLINK))
2219
- : undefined;
1722
+ };
1723
+
1724
+ // From https://github.com/adamhalasz/uniqid
1725
+ var glast;
1726
+ function now() {
1727
+ let time = Date.now();
1728
+ let last = glast || time;
1729
+ return (glast = time > last ? time : last + 1);
1730
+ }
1731
+ const Strings = {
1732
+ uniqueId({ prefix, suffix, } = {}) {
1733
+ return (prefix ? prefix : '') + now().toString(36) + (suffix ? suffix : '');
2220
1734
  },
2221
- deltaLink(annots) {
2222
- return annots.has(this.ODATA_DELTALINK)
2223
- ? decodeURIComponent(annots.get(this.ODATA_DELTALINK))
2224
- : undefined;
1735
+ titleCase(text) {
1736
+ const result = text.replace(/([a-z])([A-Z])/g, '$1 $2');
1737
+ return result
1738
+ .split(' ')
1739
+ .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
1740
+ .join(' ');
2225
1741
  },
2226
- mediaContentType(annots) {
2227
- return annots.has(this.ODATA_MEDIA_CONTENTTYPE)
2228
- ? decodeURIComponent(annots.get(this.ODATA_MEDIA_CONTENTTYPE))
2229
- : undefined;
1742
+ };
1743
+
1744
+ const Urls = {
1745
+ parseQueryString(query) {
1746
+ return query.split(PARAM_SEPARATOR).reduce((acc, param) => {
1747
+ let index = param.indexOf(VALUE_SEPARATOR);
1748
+ if (index !== -1)
1749
+ Object.assign(acc, {
1750
+ [param.substring(0, index)]: param.substring(index + 1),
1751
+ });
1752
+ return acc;
1753
+ }, {});
1754
+ },
1755
+ escapeIllegalChars(string) {
1756
+ string = string.replace(/%/g, '%25');
1757
+ string = string.replace(/\+/g, '%2B');
1758
+ string = string.replace(/\//g, '%2F');
1759
+ string = string.replace(/\?/g, '%3F');
1760
+ string = string.replace(/#/g, '%23');
1761
+ string = string.replace(/&/g, '%26');
1762
+ string = string.replace(/'/g, "''");
1763
+ return string;
2230
1764
  },
2231
1765
  };
2232
- const ODataHelper = {
2233
- //#region Version 4.0
2234
- [VERSION_4_0]: {
2235
- ...ODataVersionBaseHelper,
2236
- VALUE: 'value',
2237
- ODATA_ANNOTATION_PREFIX: '@odata',
2238
- ODATA_FUNCTION_PREFIX: '#',
2239
- //odata.id: the ID of the entity
2240
- ODATA_ID: '@odata.id',
2241
- //odata.count: the total count of a collection of entities or collection of entity references, if requested.
2242
- ODATA_COUNT: '@odata.count',
2243
- //odata.context: the context URL for a collection, entity, primitive value, or service document.
2244
- ODATA_CONTEXT: '@odata.context',
2245
- //odata.etag: the ETag of the entity
2246
- ODATA_ETAG: '@odata.etag',
2247
- ODATA_METADATA_ETAG: '@odata.metadataEtag',
2248
- //odata.type: the type of the containing {[name: string]: any} or targeted property if the type of the {[name: string]: any} or targeted property cannot be heuristically determined
2249
- ODATA_TYPE: '@odata.type',
2250
- //odata.delta
2251
- ODATA_DELTA: '@odata.delta',
2252
- //odata.remove
2253
- ODATA_REMOVE: '@odata.remove',
2254
- //odata.nextLink: the next link of a collection with partial results
2255
- ODATA_NEXTLINK: '@odata.nextLink',
2256
- //odata.deltaLink: the delta link for obtaining changes to the result, if requested
2257
- ODATA_DELTALINK: '@odata.deltaLink',
2258
- //odata.readLink: the link used to read the entity, if the edit link cannot be used to read the entity
2259
- ODATA_READLINK: '@odata.readLink',
2260
- //odata.editLink: the link used to edit/update the entity, if the entity is updatable and the odata.id does not represent a URL that can be used to edit the entity
2261
- ODATA_EDITLINK: '@odata.editLink',
2262
- //odata.associationLink: the link used to describe the relationship between this entity and related entities
2263
- ODATA_ASSOCIATIONLINK: '@odata.associationLink',
2264
- //odata.navigationLink: the link used to retrieve the values of a navigation property
2265
- ODATA_NAVIGATIONLINK: '@odata.navigationLink',
2266
- //Media entities and stream properties may in addition contain the following annotations:
2267
- //odata.mediaEtag: the ETag of the stream, as appropriate
2268
- ODATA_MEDIA_ETAG: '@odata.mediaEtag',
2269
- //odata.mediaContentType: the content type of the stream
2270
- ODATA_MEDIA_CONTENTTYPE: '@odata.mediaContentType',
2271
- //odata.mediaReadLink: the link used to read the stream
2272
- ODATA_MEDIA_READLINK: '@odata.mediaReadLink',
2273
- //odata.mediaEditLink: the link used to edit/update the stream
2274
- ODATA_MEDIA_EDITLINK: '@odata.mediaEditLink',
2275
- //http://nb-mdp-dev01:57970/$metadata#recursos/$entity
2276
- //http://nb-mdp-dev01:57970/$metadata#categorias
2277
- //http://nb-mdp-dev01:57970/$metadata#juzgados
2278
- //http://nb-mdp-dev01:57970/$metadata#Collection(SIU.Recursos.RecursoEntry)
2279
- //http://nb-mdp-dev01:57970/$metadata#categorias/$entity
2280
- //http://nb-mdp-dev01:57970/$metadata#categorias(children(children(children(children(children(children(children(children(children(children()))))))))))/$entity
2281
- //http://nb-mdp-dev01:57970/$metadata#recursos/SIU.Documentos.Documento/$entity
2282
- //http://nb-mdp-dev01:57970/$metadata#SIU.Api.Infrastructure.Storage.Backend.SiuUrls
2283
- context(annots) {
2284
- let ctx = {};
2285
- const str = annots instanceof Map
2286
- ? annots.get(this.ODATA_CONTEXT)
2287
- : annots[this.ODATA_CONTEXT];
2288
- if (typeof str === 'string') {
2289
- let index = str.indexOf('$metadata');
2290
- ctx.serviceRootUrl = str.substring(0, index);
2291
- index = str.indexOf('#');
2292
- ctx.metadataUrl = str.substring(0, index);
2293
- const parts = str.substring(index + 1).split('/');
2294
- const col = COLLECTION.exec(parts[0]);
2295
- if (col) {
2296
- ctx.type = col[1];
2297
- }
2298
- else if (parts[0].indexOf('.') !== -1) {
2299
- ctx.type = parts[0];
2300
- }
2301
- else {
2302
- const property = parts[0].match(PROPERTY);
2303
- const expand = parts[0].match(EXPAND);
2304
- ctx.entity = parts[1] === '$entity';
2305
- if (property) {
2306
- ctx.entitySet = property[1];
2307
- ctx.key = property[2];
2308
- ctx.property = parts[1];
2309
- }
2310
- else if (expand) {
2311
- ctx.entitySet = expand[1];
2312
- ctx.expand = expand[2];
2313
- }
2314
- else {
2315
- ctx.entitySet = parts[0];
2316
- }
2317
- }
1766
+
1767
+ class Expression {
1768
+ _children;
1769
+ constructor({ children, } = {}) {
1770
+ this._children = children || [];
1771
+ }
1772
+ get [Symbol.toStringTag]() {
1773
+ return 'Expression';
1774
+ }
1775
+ children() {
1776
+ return [...this._children];
1777
+ }
1778
+ length() {
1779
+ return this._children.length;
1780
+ }
1781
+ toJson() {
1782
+ return {
1783
+ $type: Types.rawType(this),
1784
+ children: this._children.map((c) => c.toJson()),
1785
+ };
1786
+ }
1787
+ resolve(parser) {
1788
+ return parser;
1789
+ }
1790
+ }
1791
+
1792
+ class ODataAnnotation {
1793
+ term;
1794
+ string;
1795
+ bool;
1796
+ int;
1797
+ permissions;
1798
+ properties;
1799
+ constructor(annot) {
1800
+ this.term = annot.term;
1801
+ Object.assign(this, annot);
1802
+ }
1803
+ }
1804
+ class ODataAnnotatable {
1805
+ annotations;
1806
+ constructor(config) {
1807
+ this.annotations = (config.annotations || []).map((annot) => new ODataAnnotation(annot));
1808
+ }
1809
+ /**
1810
+ * Find an annotation inside the annotatable.
1811
+ * @param predicate Function that returns true if the annotation match.
1812
+ * @returns The annotation that matches the predicate.
1813
+ */
1814
+ findAnnotation(predicate) {
1815
+ return this.annotations.find(predicate);
1816
+ }
1817
+ /**
1818
+ * Find an annotation inside the annotatable and return its value.
1819
+ * @param term The term of the annotation to find.
1820
+ * @returns The value of the annotation.
1821
+ */
1822
+ annotatedValue(term) {
1823
+ const reg = term instanceof RegExp ? term : new RegExp(`^${term}$`);
1824
+ const annot = this.findAnnotation((a) => reg.test(a.term));
1825
+ if (!annot) {
1826
+ return undefined;
1827
+ }
1828
+ return (annot.string ||
1829
+ annot.bool ||
1830
+ annot.int ||
1831
+ annot.permissions ||
1832
+ annot.properties);
1833
+ }
1834
+ }
1835
+
1836
+ class ODataSchemaElement extends ODataAnnotatable {
1837
+ name;
1838
+ schema;
1839
+ constructor(config, schema) {
1840
+ super(config);
1841
+ this.schema = schema;
1842
+ this.name = config.name;
1843
+ }
1844
+ get api() {
1845
+ return this.schema.api;
1846
+ }
1847
+ /**
1848
+ * Create a nicer looking title.
1849
+ * Titleize is meant for creating pretty output.
1850
+ * @param term The term of the annotation to find.
1851
+ * @returns The titleized string.
1852
+ */
1853
+ titleize(term) {
1854
+ return (term && this.annotatedValue(term)) ?? Strings.titleCase(this.name);
1855
+ }
1856
+ /**
1857
+ * Returns a full type of the structured type including the namespace/alias.
1858
+ * @param alias Use the alias of the namespace instead of the namespace.
1859
+ * @returns The string representation of the type.
1860
+ */
1861
+ type({ alias = false } = {}) {
1862
+ return `${alias ? this.schema.alias : this.schema.namespace}.${this.name}`;
1863
+ }
1864
+ /**
1865
+ * Returns a boolean indicating if the structured type is of the given type.
1866
+ * @param type String representation of the type
1867
+ * @returns True if the callable is type of the given type
1868
+ */
1869
+ isTypeOf(element) {
1870
+ const names = [`${this.schema.namespace}.${this.name}`];
1871
+ if (this.schema.alias)
1872
+ names.push(`${this.schema.alias}.${this.name}`);
1873
+ return names.includes(element.type());
1874
+ }
1875
+ /**
1876
+ * Returns a boolean indicating if the structured type is a subtype of the given type.
1877
+ * @param type String representation of the type
1878
+ * @returns True if the callable is type of the given type
1879
+ */
1880
+ isSubtypeOf(element) {
1881
+ if (this.isTypeOf(element))
1882
+ return true;
1883
+ return false;
1884
+ }
1885
+ /**
1886
+ * Returns a boolean indicating if the structured type is a supertype of the given type.
1887
+ * @param type String representation of the type
1888
+ * @returns True if the callable is type of the given type
1889
+ */
1890
+ isSupertypeOf(element) {
1891
+ if (this.isTypeOf(element))
1892
+ return true;
1893
+ return false;
1894
+ }
1895
+ }
1896
+ class ODataParserSchemaElement extends ODataSchemaElement {
1897
+ parser;
1898
+ constructor(config, schema, parser) {
1899
+ super(config, schema);
1900
+ this.parser = parser;
1901
+ }
1902
+ }
1903
+
1904
+ //https://github.com/niklasvh/base64-arraybuffer
1905
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
1906
+ // Use a lookup table to find the index.
1907
+ const lookup = new Uint8Array(256);
1908
+ for (var i = 0; i < chars.length; i++) {
1909
+ lookup[chars.charCodeAt(i)] = i;
1910
+ }
1911
+ const ArrayBuffers = {
1912
+ toArrayBuffer(v) {
1913
+ var bufferLength = v.length * 0.75, len = v.length, i, p = 0, encoded1, encoded2, encoded3, encoded4;
1914
+ if (v[v.length - 1] === '=') {
1915
+ bufferLength--;
1916
+ if (v[v.length - 2] === '=') {
1917
+ bufferLength--;
2318
1918
  }
2319
- return ctx;
2320
- },
2321
- countParam() {
2322
- return { [$COUNT]: 'true' };
2323
- },
1919
+ }
1920
+ var arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer);
1921
+ for (i = 0; i < len; i += 4) {
1922
+ encoded1 = lookup[v.charCodeAt(i)];
1923
+ encoded2 = lookup[v.charCodeAt(i + 1)];
1924
+ encoded3 = lookup[v.charCodeAt(i + 2)];
1925
+ encoded4 = lookup[v.charCodeAt(i + 3)];
1926
+ bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
1927
+ bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
1928
+ bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
1929
+ }
1930
+ return arraybuffer;
2324
1931
  },
2325
- //#endregion
2326
- //#region Version 3.0
2327
- [VERSION_3_0]: {
2328
- ...ODataVersionBaseHelper,
2329
- ODATA_ANNOTATION_PREFIX: 'odata.',
2330
- ODATA_FUNCTION_PREFIX: '',
2331
- ODATA_ID: 'odata.id',
2332
- ODATA_DELTA: 'odata.delta',
2333
- ODATA_REMOVE: 'odata.remove',
2334
- ODATA_ETAG: 'odata.etag',
2335
- ODATA_CONTEXT: 'odata.metadata',
2336
- ODATA_NEXTLINK: 'odata.nextLink',
2337
- ODATA_TYPE: 'odata.type',
2338
- ODATA_COUNT: 'odata.count',
2339
- VALUE: 'value',
2340
- context(annots) {
2341
- let ctx = {};
2342
- const str = annots instanceof Map
2343
- ? annots.get(this.ODATA_CONTEXT)
2344
- : annots[this.ODATA_CONTEXT];
2345
- if (typeof str === 'string') {
2346
- let index = str.indexOf('$metadata');
2347
- ctx.serviceRootUrl = str.substring(0, index);
2348
- index = str.indexOf('#');
2349
- ctx.metadataUrl = str.substring(0, index);
2350
- const parts = str.substring(index + 1).split('/');
2351
- ctx.entitySet = parts[0];
2352
- }
2353
- return ctx;
2354
- },
2355
- countParam() {
2356
- return { [$INLINECOUNT]: 'allpages' };
2357
- },
1932
+ toString(v) {
1933
+ var bytes = new Uint8Array(v), i, len = bytes.length, base64 = '';
1934
+ for (i = 0; i < len; i += 3) {
1935
+ base64 += chars[bytes[i] >> 2];
1936
+ base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
1937
+ base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
1938
+ base64 += chars[bytes[i + 2] & 63];
1939
+ }
1940
+ if (len % 3 === 2) {
1941
+ base64 = base64.substring(0, base64.length - 1) + '=';
1942
+ }
1943
+ else if (len % 3 === 1) {
1944
+ base64 = base64.substring(0, base64.length - 2) + '==';
1945
+ }
1946
+ return base64;
2358
1947
  },
2359
- //#endregion
2360
- //#region Version 2.0
2361
- [VERSION_2_0]: {
2362
- ...ODataVersionBaseHelper,
2363
- ODATA_ID: 'id',
2364
- ODATA_DELTA: 'delta',
2365
- ODATA_REMOVE: 'remove',
2366
- ODATA_ETAG: 'etag',
2367
- ODATA_ANNOTATION: '__metadata',
2368
- ODATA_NEXTLINK: '__next',
2369
- ODATA_COUNT: '__count',
2370
- ODATA_DEFERRED: '__deferred',
2371
- ODATA_TYPE: 'type',
2372
- VALUE: 'results',
2373
- annotations(value) {
2374
- const annots = new Map();
2375
- if (this.ODATA_ANNOTATION in value) {
2376
- Object.entries(value[this.ODATA_ANNOTATION]).forEach(([key, value]) => annots.set(key, value));
1948
+ };
1949
+
1950
+ // Core EdmTypeParserBuilder
1951
+ const EdmParser = (_d, _s, _e) => ({
1952
+ deserialize(value, options) {
1953
+ return Array.isArray(value)
1954
+ ? value.map((v) => _d(v, options))
1955
+ : _d(value, options);
1956
+ },
1957
+ serialize(value, options) {
1958
+ return Array.isArray(value)
1959
+ ? value.map((v) => _s(v, options))
1960
+ : _s(value, options);
1961
+ },
1962
+ encode(value, options) {
1963
+ return Array.isArray(value)
1964
+ ? value.map((v) => (!isRawType(v) ? _e(v, options) : v))
1965
+ : !isRawType(value)
1966
+ ? _e(value, options)
1967
+ : value;
1968
+ },
1969
+ });
1970
+ const Identity = (v) => v;
1971
+ const toNumber = (v) => Number(v);
1972
+ const toString = (v) => v.toString();
1973
+ const toBoolean = (v) => Boolean(v);
1974
+ const toDate = (v) => new Date(v);
1975
+ const EDM_PARSERS = {
1976
+ //Edm.Guid 16-byte (128-bit) unique identifier
1977
+ [EdmType.Guid]: EdmParser(Identity, Identity, (v) => raw(v)),
1978
+ //Edm.Int16 Signed 16-bit integer
1979
+ [EdmType.Int16]: EdmParser(toNumber, toNumber, toNumber),
1980
+ //Edm.String Sequence of UTF-8 characters
1981
+ [EdmType.String]: EdmParser(toString, toString, toString),
1982
+ //Edm.Boolean Binary-valued logic
1983
+ [EdmType.Boolean]: EdmParser(toBoolean, toBoolean, toBoolean),
1984
+ //Edm.Byte Unsigned 8-bit integer
1985
+ [EdmType.Byte]: EdmParser(toNumber, toNumber, toNumber),
1986
+ //Edm.SByte Signed 8-bit integer
1987
+ [EdmType.SByte]: EdmParser(toNumber, toNumber, toNumber),
1988
+ //Edm.Int32 Signed 16-bit integer
1989
+ [EdmType.Int32]: EdmParser(toNumber, toNumber, toNumber),
1990
+ //Edm.Int64 Signed 16-bit integer
1991
+ [EdmType.Int64]: EdmParser(toNumber, toNumber, toNumber),
1992
+ //Edm.Date Date without a time-zone offset
1993
+ [EdmType.Date]: EdmParser((v) => new Date(`${v}T00:00:00.000Z`), (v) => toDate(v).toISOString().substring(0, 10), (v) => raw(toDate(v).toISOString().substring(0, 10))),
1994
+ //Edm.TimeOfDay Clock time 00:00-23:59:59.999999999999
1995
+ [EdmType.TimeOfDay]: EdmParser((v) => new Date(`1970-01-01T${v}Z`), (v) => toDate(v).toISOString().substring(11, 23), (v) => raw(toDate(v).toISOString().substring(11, 23))),
1996
+ //Edm.DateTimeOffset Date and time with a time-zone offset, no leap seconds
1997
+ [EdmType.DateTimeOffset]: EdmParser(toDate, (v) => toDate(v).toISOString(), (v) => raw(toDate(v).toISOString())),
1998
+ //Edm.Duration Signed duration in days, hours, minutes, and (sub)seconds
1999
+ [EdmType.Duration]: EdmParser((v) => Durations.toDuration(v), (v) => Durations.toString(v), (v) => raw(Durations.toString(v))),
2000
+ //Edm.Decimal Numeric values with fixed precision and scale
2001
+ [EdmType.Decimal]: EdmParser(toNumber, (v, o) => {
2002
+ if (o.ieee754Compatible) {
2003
+ let vstr = v.toPrecision(o.field.precision);
2004
+ if (typeof o.field.scale === 'number') {
2005
+ vstr = parseFloat(vstr).toFixed(o.field.scale);
2006
+ }
2007
+ return vstr;
2008
+ }
2009
+ return v;
2010
+ }, (v, o) => {
2011
+ if (o.ieee754Compatible) {
2012
+ let vstr = v.toPrecision(o.field.precision);
2013
+ if (typeof o.field.scale === 'number') {
2014
+ vstr = parseFloat(vstr).toFixed(o.field.scale);
2015
+ }
2016
+ return raw(vstr);
2017
+ }
2018
+ return v;
2019
+ }),
2020
+ //Edm.Double IEEE 754 binary64 floating-point number (15-17 decimal digits)
2021
+ [EdmType.Double]: EdmParser((v) => (v === 'INF' ? Infinity : v), (v) => (v === Infinity ? 'INF' : v), (v) => raw(v === Infinity ? 'INF' : v.toString())),
2022
+ //Edm.Single IEEE 754 binary32 floating-point number (6-9 decimal digits)
2023
+ [EdmType.Single]: EdmParser((v) => (v === 'INF' ? Infinity : v), (v) => (v === Infinity ? 'INF' : v), (v) => raw(v === Infinity ? 'INF' : v.toString())),
2024
+ //Edm.Binary Binary data
2025
+ [EdmType.Binary]: EdmParser((v) => ArrayBuffers.toArrayBuffer(v), (v) => ArrayBuffers.toString(v), (v) => raw(ArrayBuffers.toString(v))),
2026
+ };
2027
+ /*
2028
+ Edm.Stream Binary data stream
2029
+ Edm.Geography Abstract base type for all Geography types
2030
+ Edm.GeographyPoint A point in a round-earth coordinate system
2031
+ Edm.GeographyLineString Line string in a round-earth coordinate system
2032
+ Edm.GeographyPolygon Polygon in a round-earth coordinate system
2033
+ Edm.GeographyMultiPoint Collection of points in a round-earth coordinate system
2034
+ Edm.GeographyMultiLineString Collection of line strings in a round-earth coordinate system
2035
+ Edm.GeographyMultiPolygon Collection of polygons in a round-earth coordinate system
2036
+ Edm.GeographyCollection Collection of arbitrary Geography values
2037
+ Edm.Geometry Abstract base type for all Geometry types
2038
+ Edm.GeometryPoint Point in a flat-earth coordinate system
2039
+ Edm.GeometryLineString Line string in a flat-earth coordinate system
2040
+ Edm.GeometryPolygon Polygon in a flat-earth coordinate system
2041
+ Edm.GeometryMultiPoint Collection of points in a flat-earth coordinate system
2042
+ Edm.GeometryMultiLineString Collection of line strings in a flat-earth coordinate system
2043
+ Edm.GeometryMultiPolygon Collection of polygons in a flat-earth coordinate system
2044
+ Edm.GeometryCollection Collection of arbitrary Geometry values
2045
+ */
2046
+
2047
+ class ODataEnumTypeFieldParser extends ODataAnnotatable {
2048
+ name;
2049
+ value;
2050
+ constructor(name, field) {
2051
+ super(field);
2052
+ this.name = name;
2053
+ this.value = field.value;
2054
+ }
2055
+ titleize(term) {
2056
+ return (term && this.annotatedValue(term)) || this.name;
2057
+ }
2058
+ }
2059
+ class ODataEnumTypeParser extends ODataAnnotatable {
2060
+ name;
2061
+ namespace;
2062
+ alias;
2063
+ flags;
2064
+ members;
2065
+ _fields;
2066
+ parserOptions;
2067
+ constructor(config, namespace, alias) {
2068
+ super(config);
2069
+ this.name = config.name;
2070
+ this.namespace = namespace;
2071
+ this.alias = alias;
2072
+ this.flags = config.flags;
2073
+ this.members = config.members;
2074
+ this._fields = Object.entries(config.fields).map(([name, f]) => new ODataEnumTypeFieldParser(name, f));
2075
+ }
2076
+ configure({ options }) {
2077
+ this.parserOptions = options;
2078
+ }
2079
+ isTypeOf(type) {
2080
+ var names = [`${this.namespace}.${this.name}`];
2081
+ if (this.alias)
2082
+ names.push(`${this.alias}.${this.name}`);
2083
+ return names.indexOf(type) !== -1;
2084
+ }
2085
+ fields(namesValue) {
2086
+ if (namesValue === undefined)
2087
+ return [...this._fields];
2088
+ if (Array.isArray(namesValue))
2089
+ return [...this._fields.filter((f) => namesValue.includes(f.value))];
2090
+ if (typeof namesValue === 'number') {
2091
+ return [
2092
+ ...this._fields.filter((f) => (this.flags && Boolean(f.value & namesValue)) ||
2093
+ f.value === namesValue),
2094
+ ];
2095
+ }
2096
+ if (typeof namesValue === 'string') {
2097
+ const names = namesValue.split(',').map((o) => o.trim());
2098
+ return this._fields.filter((f) => names.includes(f.name));
2099
+ }
2100
+ return [];
2101
+ }
2102
+ field(nameValue) {
2103
+ const field = this.fields().find((f) => f.name === nameValue || f.value === nameValue);
2104
+ //Throw error if not found
2105
+ //if (field === undefined)
2106
+ // throw new Error(`${this.name} has no field for ${nameValue}`);
2107
+ return field;
2108
+ }
2109
+ /**
2110
+ * Map the fields of the enum type.
2111
+ * @param mapper Function that maps the value to the new value
2112
+ * @returns The fields mapped by the mapper
2113
+ */
2114
+ mapFields(mapper) {
2115
+ return this.fields().map(mapper);
2116
+ }
2117
+ // Deserialize
2118
+ deserialize(value, options) {
2119
+ // string -> number
2120
+ const parserOptions = { ...this.parserOptions, ...options };
2121
+ if (this.flags) {
2122
+ return this.fields(value).reduce((acc, f) => acc | f.value, 0);
2123
+ }
2124
+ else {
2125
+ return this.field(value)?.value;
2126
+ }
2127
+ }
2128
+ // Serialize
2129
+ serialize(value, options) {
2130
+ // Enum are string | number
2131
+ // string | number -> string
2132
+ const parserOptions = { ...this.parserOptions, ...options };
2133
+ if (this.flags) {
2134
+ let names = this.fields(value).map((f) => f.name);
2135
+ if (names.length === 0)
2136
+ names = [`${value}`];
2137
+ return !parserOptions?.stringAsEnum
2138
+ ? `${this.namespace}.${this.name}'${names.join(', ')}'`
2139
+ : names.join(', ');
2140
+ }
2141
+ else {
2142
+ let name = this.field(value)?.name;
2143
+ if (name === undefined)
2144
+ name = `${value}`;
2145
+ return !parserOptions?.stringAsEnum
2146
+ ? `${this.namespace}.${this.name}'${name}'`
2147
+ : name;
2148
+ }
2149
+ }
2150
+ //Encode
2151
+ encode(value, options) {
2152
+ const parserOptions = { ...this.parserOptions, ...options };
2153
+ const serialized = this.serialize(value, parserOptions);
2154
+ if (serialized === undefined)
2155
+ return undefined;
2156
+ return parserOptions?.stringAsEnum
2157
+ ? raw(`'${serialized}'`)
2158
+ : raw(serialized);
2159
+ }
2160
+ // Json Schema
2161
+ toJsonSchema() {
2162
+ return this.flags
2163
+ ? {
2164
+ title: this.name,
2165
+ type: JsonType.array,
2166
+ items: {
2167
+ type: JsonType.integer,
2168
+ },
2377
2169
  }
2378
- return annots;
2379
- },
2380
- context(annots) {
2381
- let ctx = {};
2382
- return ctx;
2383
- },
2384
- attributes(value, metadata) {
2385
- return value;
2386
- },
2387
- countParam() {
2388
- return { [$INLINECOUNT]: 'allpages' };
2389
- },
2390
- },
2391
- //#endregion
2392
- };
2170
+ : {
2171
+ type: JsonType.integer,
2172
+ enum: this._fields.map((f) => f.value),
2173
+ };
2174
+ }
2175
+ validate(value, { method, navigation = false, } = {}) {
2176
+ if (this.flags) {
2177
+ let fields = this.fields(value);
2178
+ return value && fields.length === 0 ? ['mismatch'] : undefined;
2179
+ }
2180
+ else {
2181
+ return this.fields(value).length !== 1 ? ['mismatch'] : undefined;
2182
+ }
2183
+ }
2184
+ unpack(value) {
2185
+ return this.fields(value).map((f) => f.value);
2186
+ }
2187
+ pack(value) {
2188
+ return this.fields(value).reduce((acc, v) => acc | v.value, 0);
2189
+ }
2190
+ }
2393
2191
 
2394
2192
  class ODataEntityTypeKey {
2395
2193
  name;
@@ -3555,7 +3353,7 @@ class CountExpression extends Expression {
3555
3353
  return opts({
3556
3354
  t: FieldFactory(),
3557
3355
  e: () => new CountExpression(),
3558
- }, current);
3356
+ }, current ?? new CountExpression());
3559
3357
  }
3560
3358
  _add(node) {
3561
3359
  this._children.push(node);
@@ -3597,8 +3395,8 @@ class FilterExpression extends Expression {
3597
3395
  _negated;
3598
3396
  constructor({ children, connector, negated, } = {}) {
3599
3397
  super({ children });
3600
- this._connector = connector || 'and';
3601
- this._negated = negated || false;
3398
+ this._connector = connector ?? 'and';
3399
+ this._negated = negated ?? false;
3602
3400
  }
3603
3401
  get [Symbol.toStringTag]() {
3604
3402
  return 'FilterExpression';
@@ -3609,7 +3407,7 @@ class FilterExpression extends Expression {
3609
3407
  t: FieldFactory(),
3610
3408
  o: operators,
3611
3409
  f: functions,
3612
- }, current);
3410
+ }, current ?? new FilterExpression());
3613
3411
  }
3614
3412
  toJson() {
3615
3413
  const json = super.toJson();
@@ -3767,6 +3565,9 @@ class FilterExpression extends Expression {
3767
3565
  isof(left, type) {
3768
3566
  return this._add(syntax.isof(left, type));
3769
3567
  }
3568
+ combine(exp, connector = 'and') {
3569
+ return this._add(exp, connector);
3570
+ }
3770
3571
  }
3771
3572
 
3772
3573
  class SearchTerm {
@@ -3804,8 +3605,8 @@ class SearchExpression extends Expression {
3804
3605
  _negated;
3805
3606
  constructor({ children, connector, negated, } = {}) {
3806
3607
  super({ children });
3807
- this._connector = connector || 'AND';
3808
- this._negated = negated || false;
3608
+ this._connector = connector ?? 'AND';
3609
+ this._negated = negated ?? false;
3809
3610
  }
3810
3611
  get [Symbol.toStringTag]() {
3811
3612
  return 'SearchExpression';
@@ -3813,7 +3614,7 @@ class SearchExpression extends Expression {
3813
3614
  static factory(opts, current) {
3814
3615
  return opts({
3815
3616
  e: (connector = 'AND') => new SearchExpression({ connector }),
3816
- }, current);
3617
+ }, current ?? new SearchExpression());
3817
3618
  }
3818
3619
  _add(node, connector) {
3819
3620
  if (connector !== undefined && this._connector !== connector) {
@@ -3908,6 +3709,9 @@ class SearchExpression extends Expression {
3908
3709
  term(value) {
3909
3710
  return this._add(new SearchTerm(value));
3910
3711
  }
3712
+ combine(expression, connector = 'AND') {
3713
+ return this._add(expression, connector);
3714
+ }
3911
3715
  }
3912
3716
 
3913
3717
  class GroupByTransformations extends Expression {
@@ -3915,8 +3719,8 @@ class GroupByTransformations extends Expression {
3915
3719
  aliases;
3916
3720
  constructor({ children, methods, aliases, } = {}) {
3917
3721
  super({ children });
3918
- this.methods = methods || [];
3919
- this.aliases = aliases || [];
3722
+ this.methods = methods ?? [];
3723
+ this.aliases = aliases ?? [];
3920
3724
  }
3921
3725
  get [Symbol.toStringTag]() {
3922
3726
  return 'GroupByTransformations';
@@ -3991,7 +3795,7 @@ class ApplyExpression extends Expression {
3991
3795
  return opts({
3992
3796
  t: FieldFactory(),
3993
3797
  e: () => new ApplyExpression(),
3994
- }, current);
3798
+ }, current ?? new ApplyExpression());
3995
3799
  }
3996
3800
  toJson() {
3997
3801
  const json = super.toJson();
@@ -4102,7 +3906,7 @@ class ApplyExpression extends Expression {
4102
3906
  orderBy(
4103
3907
  opts: (
4104
3908
  builder: OrderByExpressionBuilder<T>,
4105
- current?: OrderByExpression<T>
3909
+ current: OrderByExpression<T>
4106
3910
  ) => OrderByExpression<T>,
4107
3911
  current?: OrderByExpression<T>
4108
3912
  ) {
@@ -4111,7 +3915,7 @@ class ApplyExpression extends Expression {
4111
3915
  t: FieldFactory<Required<T>>(),
4112
3916
  e: () => new OrderByExpression<T>(),
4113
3917
  },
4114
- current
3918
+ current ?? new OrderByExpression<T>()
4115
3919
  ) as OrderByExpression<T>;
4116
3920
  return this._add(transformations.orderby(exp));
4117
3921
  }
@@ -4188,7 +3992,7 @@ class OrderByExpression extends Expression {
4188
3992
  return opts({
4189
3993
  t: FieldFactory(),
4190
3994
  e: () => new OrderByExpression(),
4191
- }, current);
3995
+ }, current ?? new OrderByExpression());
4192
3996
  }
4193
3997
  _add(node) {
4194
3998
  this._children.push(node);
@@ -4220,6 +4024,9 @@ class OrderByExpression extends Expression {
4220
4024
  descending(field) {
4221
4025
  return this._add(new OrderByField(field, 'desc'));
4222
4026
  }
4027
+ combine(expression) {
4028
+ return this._add(expression);
4029
+ }
4223
4030
  }
4224
4031
 
4225
4032
  class SelectExpression extends Expression {
@@ -4233,7 +4040,7 @@ class SelectExpression extends Expression {
4233
4040
  return opts({
4234
4041
  t: FieldFactory(),
4235
4042
  e: () => new SelectExpression(),
4236
- }, current);
4043
+ }, current ?? new SelectExpression());
4237
4044
  }
4238
4045
  toJson() {
4239
4046
  const json = super.toJson();
@@ -4267,6 +4074,9 @@ class SelectExpression extends Expression {
4267
4074
  fields.forEach((f) => this._add(f));
4268
4075
  return this;
4269
4076
  }
4077
+ combine(expression) {
4078
+ return this._add(expression);
4079
+ }
4270
4080
  }
4271
4081
 
4272
4082
  class ExpandField {
@@ -4381,7 +4191,7 @@ class ExpandExpression extends Expression {
4381
4191
  return opts({
4382
4192
  t: FieldFactory(),
4383
4193
  e: () => new ExpandExpression(),
4384
- }, current);
4194
+ }, current ?? new ExpandExpression());
4385
4195
  }
4386
4196
  toJson() {
4387
4197
  const json = super.toJson();
@@ -4412,6 +4222,9 @@ class ExpandExpression extends Expression {
4412
4222
  opts(node);
4413
4223
  return this._add(node);
4414
4224
  }
4225
+ combine(expression) {
4226
+ return this._add(expression);
4227
+ }
4415
4228
  }
4416
4229
 
4417
4230
  const FieldFactory = (names = []) => new Proxy({ _names: names }, {
@@ -5177,7 +4990,7 @@ class ComputeExpression extends Expression {
5177
4990
  names;
5178
4991
  constructor({ children, names, } = {}) {
5179
4992
  super({ children });
5180
- this.names = names || [];
4993
+ this.names = names ?? [];
5181
4994
  }
5182
4995
  get [Symbol.toStringTag]() {
5183
4996
  return 'ComputeExpression';
@@ -5186,7 +4999,7 @@ class ComputeExpression extends Expression {
5186
4999
  return opts({
5187
5000
  t: FieldFactory(),
5188
5001
  e: () => new ComputeExpression(),
5189
- }, current);
5002
+ }, current ?? new ComputeExpression());
5190
5003
  }
5191
5004
  toJson() {
5192
5005
  const json = super.toJson();
@@ -5633,6 +5446,116 @@ class ODataQueryOptionsHandler {
5633
5446
  }
5634
5447
  this.paging(options);
5635
5448
  }
5449
+ /**
5450
+ * Combine the given query options with the current query.
5451
+ * @param options The query to be combined.
5452
+ */
5453
+ combine(options) {
5454
+ if (options.select !== undefined) {
5455
+ if (options.select instanceof SelectExpression) {
5456
+ const current = this.options.expression(QueryOption.select);
5457
+ if (current === undefined) {
5458
+ this.options.expression(QueryOption.select, options.select);
5459
+ }
5460
+ else {
5461
+ current.combine(options.select);
5462
+ }
5463
+ }
5464
+ else if (options.select !== null) {
5465
+ const current = this.options.option(QueryOption.select);
5466
+ if (current === undefined) {
5467
+ this.options.option(QueryOption.select, options.select);
5468
+ }
5469
+ else {
5470
+ this.options.option(QueryOption.select, [current, options.select]);
5471
+ }
5472
+ }
5473
+ else {
5474
+ this.options.remove(QueryOption.select);
5475
+ }
5476
+ }
5477
+ if (options.expand !== undefined) {
5478
+ if (options.expand instanceof ExpandExpression) {
5479
+ const current = this.options.expression(QueryOption.expand);
5480
+ if (current === undefined) {
5481
+ this.options.expression(QueryOption.expand, options.expand);
5482
+ }
5483
+ else {
5484
+ current.combine(options.expand);
5485
+ }
5486
+ }
5487
+ else if (options.expand !== null) {
5488
+ const current = this.options.option(QueryOption.expand);
5489
+ if (current === undefined) {
5490
+ this.options.option(QueryOption.expand, options.expand);
5491
+ }
5492
+ }
5493
+ else {
5494
+ this.options.remove(QueryOption.expand);
5495
+ }
5496
+ }
5497
+ if (options.search !== undefined) {
5498
+ if (options.search instanceof SearchExpression) {
5499
+ const current = this.options.expression(QueryOption.search);
5500
+ if (current === undefined) {
5501
+ this.options.expression(QueryOption.search, options.search);
5502
+ }
5503
+ else {
5504
+ current.combine(options.search);
5505
+ }
5506
+ }
5507
+ else if (options.search !== null) {
5508
+ const current = this.options.option(QueryOption.search);
5509
+ if (current === undefined) {
5510
+ this.options.option(QueryOption.search, options.search);
5511
+ }
5512
+ }
5513
+ else {
5514
+ this.options.remove(QueryOption.search);
5515
+ }
5516
+ }
5517
+ if (options.filter !== undefined) {
5518
+ if (options.filter instanceof FilterExpression) {
5519
+ const current = this.options.expression(QueryOption.filter);
5520
+ if (current === undefined) {
5521
+ this.options.expression(QueryOption.filter, options.filter);
5522
+ }
5523
+ else {
5524
+ current.combine(options.filter);
5525
+ }
5526
+ }
5527
+ else if (options.filter !== null) {
5528
+ const current = this.options.option(QueryOption.filter);
5529
+ if (current === undefined) {
5530
+ this.options.option(QueryOption.filter, options.filter);
5531
+ }
5532
+ }
5533
+ else {
5534
+ this.options.remove(QueryOption.filter);
5535
+ }
5536
+ }
5537
+ if (options.orderBy !== undefined) {
5538
+ if (options.orderBy instanceof OrderByExpression) {
5539
+ const current = this.options.expression(QueryOption.orderBy);
5540
+ if (current === undefined) {
5541
+ this.options.expression(QueryOption.orderBy, options.orderBy);
5542
+ }
5543
+ else {
5544
+ current.combine(options.orderBy);
5545
+ }
5546
+ }
5547
+ else if (options.orderBy !== null) {
5548
+ const current = this.options.option(QueryOption.filter);
5549
+ if (current === undefined) {
5550
+ this.options.option(QueryOption.orderBy, options.orderBy);
5551
+ }
5552
+ }
5553
+ else {
5554
+ this.options.remove(QueryOption.orderBy);
5555
+ }
5556
+ }
5557
+ this.paging(options);
5558
+ }
5636
5559
  toJson() {
5637
5560
  return this.options.toJson();
5638
5561
  }
@@ -5642,6 +5565,13 @@ class ODataQueryOptionsHandler {
5642
5565
  toString({ escape, parser, } = {}) {
5643
5566
  return this.options.toString({ escape, parser });
5644
5567
  }
5568
+ pathAndParams({ escape, parser, options, } = {}) {
5569
+ return this.options.pathAndParams({
5570
+ escape,
5571
+ parser,
5572
+ options,
5573
+ });
5574
+ }
5645
5575
  }
5646
5576
 
5647
5577
  // Create a path and params tuple from the query options
@@ -10380,62 +10310,7 @@ class ODataResponse extends HttpResponse {
10380
10310
  : payload);
10381
10311
  if (value !== null)
10382
10312
  value = this.resource.deserialize(value, options);
10383
- return value;
10384
- }
10385
- }
10386
-
10387
- class ODataInStorageCache extends ODataCache {
10388
- name;
10389
- storage;
10390
- constructor({ name, storage = sessionStorage, timeout, }) {
10391
- super({ timeout });
10392
- this.name = name;
10393
- this.storage = storage;
10394
- this.restore();
10395
- window.addEventListener('beforeunload', () => this.store());
10396
- }
10397
- /**
10398
- * Store the cache in the storage
10399
- */
10400
- store() {
10401
- this.storage.setItem(this.name, JSON.stringify(Array.from(this.entries.entries())));
10402
- }
10403
- /**
10404
- * Restore the cache from the storage
10405
- */
10406
- restore() {
10407
- this.entries = new Map(JSON.parse(this.storage.getItem(this.name) || '[]'));
10408
- }
10409
- /**
10410
- * Flush the cache and clean the storage
10411
- */
10412
- flush() {
10413
- super.flush();
10414
- this.store();
10415
- }
10416
- /**
10417
- * Store the response in the cache
10418
- * @param req The request with the resource to store the response
10419
- * @param res The response to store in the cache
10420
- */
10421
- putResponse(req, res) {
10422
- const scope = this.scope(req);
10423
- const tags = this.tags(res);
10424
- this.put(req.cacheKey, res.toJson(), {
10425
- timeout: res.options.maxAge,
10426
- scope,
10427
- tags,
10428
- });
10429
- }
10430
- /**
10431
- * Restore the response from the cache
10432
- * @param req The request with the resource to get the response
10433
- * @returns The response from the cache
10434
- */
10435
- getResponse(req) {
10436
- const scope = this.scope(req);
10437
- const data = this.get(req.cacheKey, { scope });
10438
- return data !== undefined ? ODataResponse.fromJson(req, data) : undefined;
10313
+ return value;
10439
10314
  }
10440
10315
  }
10441
10316
 
@@ -11223,7 +11098,9 @@ class ODataCollection {
11223
11098
  result = 1;
11224
11099
  else if (value1 == null && value2 == null)
11225
11100
  result = 0;
11226
- else if ((typeof value1 == 'string' || value1 instanceof String) && value1.localeCompare && value1 != value2)
11101
+ else if ((typeof value1 == 'string' || value1 instanceof String) &&
11102
+ value1.localeCompare &&
11103
+ value1 != value2)
11227
11104
  result = value1.localeCompare(value2);
11228
11105
  else if (value1 == value2)
11229
11106
  return by.length - 1 > index ? this._compare(e1, e2, by, index + 1) : 0;
@@ -13159,7 +13036,7 @@ class ODataApi {
13159
13036
  ...config.options,
13160
13037
  version: this.version,
13161
13038
  });
13162
- this.cache = config.cache ?? new ODataInMemoryCache();
13039
+ this.cache = config.cache;
13163
13040
  this.errorHandler = config.errorHandler;
13164
13041
  this.parsers = new Map(Object.entries(config.parsers ?? EDM_PARSERS));
13165
13042
  this.schemas = (config.schemas ?? []).map((schema) => new ODataSchema(schema, this));
@@ -13304,7 +13181,9 @@ class ODataApi {
13304
13181
  if (options.observe === 'events') {
13305
13182
  return res$;
13306
13183
  }
13307
- res$ = this.cache.handleRequest(req, res$);
13184
+ if (this.cache !== undefined) {
13185
+ res$ = this.cache.handleRequest(req, res$);
13186
+ }
13308
13187
  switch (options.observe || 'body') {
13309
13188
  case 'body':
13310
13189
  switch (options.responseType) {
@@ -13906,10 +13785,10 @@ class ODataClient {
13906
13785
  put(resource, body, options = {}) {
13907
13786
  return this.request('PUT', resource, addBody(options, body));
13908
13787
  }
13909
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataClient, deps: [{ token: i1.HttpClient }, { token: ODataConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable });
13910
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataClient });
13788
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataClient, deps: [{ token: i1.HttpClient }, { token: ODataConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable });
13789
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataClient });
13911
13790
  }
13912
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataClient, decorators: [{
13791
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataClient, decorators: [{
13913
13792
  type: Injectable
13914
13793
  }], ctorParameters: () => [{ type: i1.HttpClient }, { type: ODataConfigLoader }] });
13915
13794
 
@@ -14193,10 +14072,10 @@ class ODataServiceFactory {
14193
14072
  };
14194
14073
  return new Service(this.client, singletonName, apiNameOrEntityType);
14195
14074
  }
14196
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataServiceFactory, deps: [{ token: ODataClient }], target: i0.ɵɵFactoryTarget.Injectable });
14197
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataServiceFactory });
14075
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataServiceFactory, deps: [{ token: ODataClient }], target: i0.ɵɵFactoryTarget.Injectable });
14076
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataServiceFactory });
14198
14077
  }
14199
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataServiceFactory, decorators: [{
14078
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataServiceFactory, decorators: [{
14200
14079
  type: Injectable
14201
14080
  }], ctorParameters: () => [{ type: ODataClient }] });
14202
14081
 
@@ -14236,11 +14115,11 @@ class ODataModule {
14236
14115
  ],
14237
14116
  };
14238
14117
  }
14239
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
14240
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.1.0", ngImport: i0, type: ODataModule, imports: [CommonModule, HttpClientModule] });
14241
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataModule, providers: [ODataClient, ODataServiceFactory], imports: [CommonModule, HttpClientModule] });
14118
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
14119
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.12", ngImport: i0, type: ODataModule, imports: [CommonModule, HttpClientModule] });
14120
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataModule, providers: [ODataClient, ODataServiceFactory], imports: [CommonModule, HttpClientModule] });
14242
14121
  }
14243
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ODataModule, decorators: [{
14122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ODataModule, decorators: [{
14244
14123
  type: NgModule,
14245
14124
  args: [{
14246
14125
  imports: [CommonModule, HttpClientModule],
@@ -14248,6 +14127,263 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
14248
14127
  }]
14249
14128
  }] });
14250
14129
 
14130
+ class ODataBaseCache {
14131
+ timeout;
14132
+ entries;
14133
+ constructor({ timeout = DEFAULT_TIMEOUT }) {
14134
+ this.timeout = timeout;
14135
+ this.entries = new Map();
14136
+ }
14137
+ /**
14138
+ * Using the resource on the request build an array of string to identify the scope of the request
14139
+ * @param req The request with the resource to build the scope
14140
+ * @returns Array of string to identify the scope of the request
14141
+ */
14142
+ scope(req) {
14143
+ const segments = req.resource.cloneSegments();
14144
+ return segments.segments({ key: true }).reduce((acc, s) => {
14145
+ if (s.name === PathSegment.entitySet)
14146
+ acc = [...acc, s.path()];
14147
+ return acc;
14148
+ }, ['request']);
14149
+ }
14150
+ /**
14151
+ * Using the odata context on the response build an array of string to identify the tags of the response
14152
+ * @param res The response to build the tags
14153
+ * @returns Array of string to identify the tags of the response
14154
+ */
14155
+ tags(res) {
14156
+ const tags = [];
14157
+ const context = res.context;
14158
+ if (context.entitySet) {
14159
+ tags.push(context.key
14160
+ ? `${context.entitySet}(${context.key})`
14161
+ : context.entitySet);
14162
+ }
14163
+ if (context.type)
14164
+ tags.push(context.type);
14165
+ return tags;
14166
+ }
14167
+ /**
14168
+ * Build an entry from a payload and some options
14169
+ * @param payload The payload to store in the cache
14170
+ * @param timeout The timeout for the entry
14171
+ * @param tags The tags for the entry
14172
+ * @returns The entry to store in the cache
14173
+ */
14174
+ buildEntry(payload, { timeout, tags }) {
14175
+ return {
14176
+ payload,
14177
+ lastRead: Date.now(),
14178
+ timeout: timeout || this.timeout,
14179
+ tags: tags || [],
14180
+ };
14181
+ }
14182
+ /**
14183
+ * Build a key from store an entry in the cache
14184
+ * @param names The names of the entry
14185
+ * @returns The key for the entry
14186
+ */
14187
+ buildKey(names) {
14188
+ return names.join(CACHE_KEY_SEPARATOR);
14189
+ }
14190
+ /**
14191
+ * Put some payload in the cache
14192
+ * @param name The name for the entry
14193
+ * @param payload The payload to store in the cache
14194
+ * @param timeout The timeout for the entry
14195
+ * @param scope The scope for the entry
14196
+ * @param tags The tags for the entry
14197
+ */
14198
+ put(name, payload, { timeout, scope, tags, } = {}) {
14199
+ const entry = this.buildEntry(payload, { timeout, tags });
14200
+ const key = this.buildKey([...(scope || []), name]);
14201
+ this.entries.set(key, entry);
14202
+ this.forget();
14203
+ }
14204
+ /**
14205
+ * Return the payload from the cache if it exists and is not expired
14206
+ * @param name The name of the entry
14207
+ * @param scope The scope of the entry
14208
+ * @returns The payload of the entry
14209
+ */
14210
+ get(name, { scope } = {}) {
14211
+ const key = this.buildKey([...(scope || []), name]);
14212
+ const entry = this.entries.get(key);
14213
+ return entry !== undefined && !this.isExpired(entry)
14214
+ ? entry.payload
14215
+ : undefined;
14216
+ }
14217
+ /**
14218
+ * Remove all cache entries that are matching with the given options
14219
+ * @param options The options to forget
14220
+ */
14221
+ forget({ name, scope = [], tags = [], } = {}) {
14222
+ if (name !== undefined)
14223
+ scope.push(name);
14224
+ const key = scope.length > 0 ? this.buildKey(scope) : undefined;
14225
+ this.entries.forEach((entry, k) => {
14226
+ if (this.isExpired(entry) || // Expired
14227
+ (key !== undefined && k.startsWith(key)) || // Key
14228
+ (tags.length > 0 && tags.some((t) => entry.tags.indexOf(t) !== -1)) // Tags
14229
+ ) {
14230
+ this.entries.delete(k);
14231
+ }
14232
+ });
14233
+ }
14234
+ /**
14235
+ * Remove all cache entries
14236
+ */
14237
+ flush() {
14238
+ this.entries = new Map();
14239
+ }
14240
+ /**
14241
+ * Check if the entry is expired
14242
+ * @param entry The cache entry
14243
+ * @returns Boolean indicating if the entry is expired
14244
+ */
14245
+ isExpired(entry) {
14246
+ return entry.lastRead < Date.now() - (entry.timeout || this.timeout) * 1000;
14247
+ }
14248
+ /**
14249
+ * Using the request, handle the fetching of the response
14250
+ * @param req The request to fetch
14251
+ * @param res$ Observable of the response
14252
+ * @returns
14253
+ */
14254
+ handleRequest(req, res$) {
14255
+ return req.isFetch()
14256
+ ? this.handleFetch(req, res$)
14257
+ : req.isMutate()
14258
+ ? this.handleMutate(req, res$)
14259
+ : res$;
14260
+ }
14261
+ handleFetch(req, res$) {
14262
+ const policy = req.fetchPolicy;
14263
+ const cached = this.getResponse(req);
14264
+ if (policy === 'no-cache') {
14265
+ return res$;
14266
+ }
14267
+ if (policy === 'cache-only') {
14268
+ if (cached) {
14269
+ return of(cached);
14270
+ }
14271
+ else {
14272
+ return throwError(() => new Error('No Cached'));
14273
+ }
14274
+ }
14275
+ if (policy === 'cache-first' ||
14276
+ policy === 'cache-and-network' ||
14277
+ policy === 'network-only') {
14278
+ res$ = res$.pipe(tap((res) => {
14279
+ if (res.options.cacheability !== 'no-store')
14280
+ this.putResponse(req, res);
14281
+ }));
14282
+ }
14283
+ return cached !== undefined && policy !== 'network-only'
14284
+ ? policy === 'cache-and-network'
14285
+ ? res$.pipe(startWith(cached))
14286
+ : of(cached)
14287
+ : res$;
14288
+ }
14289
+ handleMutate(req, res$) {
14290
+ const requests = req.isBatch()
14291
+ ? req.resource
14292
+ .requests()
14293
+ .filter((r) => r.isMutate())
14294
+ : [req];
14295
+ for (var r of requests) {
14296
+ const scope = this.scope(r);
14297
+ this.forget({ scope });
14298
+ }
14299
+ return res$;
14300
+ }
14301
+ }
14302
+
14303
+ class ODataInMemoryCache extends ODataBaseCache {
14304
+ constructor({ timeout } = {}) {
14305
+ super({ timeout });
14306
+ }
14307
+ /**
14308
+ * Store the response in the cache
14309
+ * @param req The request with the resource to store the response
14310
+ * @param res The response to store in the cache
14311
+ */
14312
+ putResponse(req, res) {
14313
+ let scope = this.scope(req);
14314
+ let tags = this.tags(res);
14315
+ this.put(req.cacheKey, res, {
14316
+ timeout: res.options.maxAge,
14317
+ scope,
14318
+ tags,
14319
+ });
14320
+ }
14321
+ /**
14322
+ * Restore the response from the cache
14323
+ * @param req The request with the resource to get the response
14324
+ * @returns The response from the cache
14325
+ */
14326
+ getResponse(req) {
14327
+ let scope = this.scope(req);
14328
+ return this.get(req.cacheKey, { scope });
14329
+ }
14330
+ }
14331
+
14332
+ class ODataInStorageCache extends ODataBaseCache {
14333
+ name;
14334
+ storage;
14335
+ constructor({ name, storage = sessionStorage, timeout, }) {
14336
+ super({ timeout });
14337
+ this.name = name;
14338
+ this.storage = storage;
14339
+ this.restore();
14340
+ window.addEventListener('beforeunload', () => this.store());
14341
+ }
14342
+ /**
14343
+ * Store the cache in the storage
14344
+ */
14345
+ store() {
14346
+ this.storage.setItem(this.name, JSON.stringify(Array.from(this.entries.entries())));
14347
+ }
14348
+ /**
14349
+ * Restore the cache from the storage
14350
+ */
14351
+ restore() {
14352
+ this.entries = new Map(JSON.parse(this.storage.getItem(this.name) || '[]'));
14353
+ }
14354
+ /**
14355
+ * Flush the cache and clean the storage
14356
+ */
14357
+ flush() {
14358
+ super.flush();
14359
+ this.store();
14360
+ }
14361
+ /**
14362
+ * Store the response in the cache
14363
+ * @param req The request with the resource to store the response
14364
+ * @param res The response to store in the cache
14365
+ */
14366
+ putResponse(req, res) {
14367
+ const scope = this.scope(req);
14368
+ const tags = this.tags(res);
14369
+ this.put(req.cacheKey, res.toJson(), {
14370
+ timeout: res.options.maxAge,
14371
+ scope,
14372
+ tags,
14373
+ });
14374
+ }
14375
+ /**
14376
+ * Restore the response from the cache
14377
+ * @param req The request with the resource to get the response
14378
+ * @returns The response from the cache
14379
+ */
14380
+ getResponse(req) {
14381
+ const scope = this.scope(req);
14382
+ const data = this.get(req.cacheKey, { scope });
14383
+ return data !== undefined ? ODataResponse.fromJson(req, data) : undefined;
14384
+ }
14385
+ }
14386
+
14251
14387
  /*
14252
14388
  * Public API Surface of angular-odata
14253
14389
  */
@@ -14256,5 +14392,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
14256
14392
  * Generated bundle index. Do not edit.
14257
14393
  */
14258
14394
 
14259
- export { Aggregate, ApplyExpression, ArithmeticFunctions, ArithmeticOperators, BUBBLES, CollectionFunctions, ComputeExpression, ConditionalFunctions, DateAndTimeFunctions, Dates, Durations, EDM_PARSERS, EdmType, Enums, ExpandExpression, ExpandField, Expression, FieldFactory, FilterExpression, Function, GeoFunctions, GroupBy, GroupByTransformations, Grouping, GroupingOperators, Http, INCLUDE_DEEP, INCLUDE_SHALLOW, ITEM_ROOT, JsonType, Lambda, LambdaOperators, LogicalOperators, Model, ModelField, NONE_PARSER, ODATA_CONFIG, OData, ODataActionResource, ODataAnnotations, ODataApi, ODataBaseService, ODataBatchRequest, ODataBatchResource, ODataCache, ODataCallable, ODataCallableParser, ODataClient, ODataCollection, ODataConfigAsyncLoader, ODataConfigLoader, ODataConfigSyncLoader, ODataCountResource, ODataEntitiesAnnotations, ODataEntityAnnotations, ODataEntityContainer, ODataEntityResource, ODataEntitySet, ODataEntitySetResource, ODataEntitySetService, ODataEntityTypeKey, ODataEnumType, ODataEnumTypeFieldParser, ODataEnumTypeParser, ODataFunctionResource, ODataFunctions, ODataInMemoryCache, ODataInStorageCache, ODataMediaResource, ODataMetadata, ODataMetadataLoader, ODataMetadataParser, ODataMetadataResource, ODataModel, ODataModelAttribute, ODataModelEvent, ODataModelEventEmitter, ODataModelEventType, ODataModelField, ODataModelOptions, ODataModelState, ODataModule, ODataNavigationPropertyResource, ODataOperators, ODataParameterParser, ODataPathSegments, ODataPathSegmentsHandler, ODataPropertyAnnotations, ODataPropertyResource, ODataQueryOptionHandler, ODataQueryOptions, ODataQueryOptionsHandler, ODataReferenceResource, ODataReferential, ODataRequest, ODataResource, ODataResponse, ODataSchema, ODataServiceFactory, ODataSettings, ODataSingleton, ODataSingletonResource, ODataSingletonService, ODataStructuredType, ODataStructuredTypeFieldParser, ODataStructuredTypeParser, ODataSyntax, ODataTransformations, ODataValueResource, Objects, Operator, OrderByExpression, OrderByField, PathSegment, QueryCustomTypes, QueryOption, RenderableFactory, SearchExpression, SearchTerm, SegmentHandler, SelectExpression, StandardAggregateMethods, StringAndCollectionFunctions, StringFunctions, Strings, Transformations, Type, TypeFunctions, Types, Urls, alias, binary, buildPathAndQuery, createSyncLoader, duration, encode, functions, isQueryCustomType, isRawType, normalizeValue, operators, pathAndParamsFromQueryOptions, pathAndParamsFromSegments, provideODataClient, raw, render, resolve, syntax, transformations };
14395
+ export { Aggregate, ApplyExpression, ArithmeticFunctions, ArithmeticOperators, BUBBLES, CollectionFunctions, ComputeExpression, ConditionalFunctions, DateAndTimeFunctions, Dates, Durations, EDM_PARSERS, EdmType, Enums, ExpandExpression, ExpandField, Expression, FieldFactory, FilterExpression, Function, GeoFunctions, GroupBy, GroupByTransformations, Grouping, GroupingOperators, Http, INCLUDE_DEEP, INCLUDE_SHALLOW, ITEM_ROOT, JsonType, Lambda, LambdaOperators, LogicalOperators, Model, ModelField, NONE_PARSER, ODATA_CONFIG, OData, ODataActionResource, ODataAnnotations, ODataApi, ODataBaseCache, ODataBaseService, ODataBatchRequest, ODataBatchResource, ODataCallable, ODataCallableParser, ODataClient, ODataCollection, ODataConfigAsyncLoader, ODataConfigLoader, ODataConfigSyncLoader, ODataCountResource, ODataEntitiesAnnotations, ODataEntityAnnotations, ODataEntityContainer, ODataEntityResource, ODataEntitySet, ODataEntitySetResource, ODataEntitySetService, ODataEntityTypeKey, ODataEnumType, ODataEnumTypeFieldParser, ODataEnumTypeParser, ODataFunctionResource, ODataFunctions, ODataInMemoryCache, ODataInStorageCache, ODataMediaResource, ODataMetadata, ODataMetadataLoader, ODataMetadataParser, ODataMetadataResource, ODataModel, ODataModelAttribute, ODataModelEvent, ODataModelEventEmitter, ODataModelEventType, ODataModelField, ODataModelOptions, ODataModelState, ODataModule, ODataNavigationPropertyResource, ODataOperators, ODataParameterParser, ODataPathSegments, ODataPathSegmentsHandler, ODataPropertyAnnotations, ODataPropertyResource, ODataQueryOptionHandler, ODataQueryOptions, ODataQueryOptionsHandler, ODataReferenceResource, ODataReferential, ODataRequest, ODataResource, ODataResponse, ODataSchema, ODataServiceFactory, ODataSettings, ODataSingleton, ODataSingletonResource, ODataSingletonService, ODataStructuredType, ODataStructuredTypeFieldParser, ODataStructuredTypeParser, ODataSyntax, ODataTransformations, ODataValueResource, Objects, Operator, OrderByExpression, OrderByField, PathSegment, QueryCustomTypes, QueryOption, RenderableFactory, SearchExpression, SearchTerm, SegmentHandler, SelectExpression, StandardAggregateMethods, StringAndCollectionFunctions, StringFunctions, Strings, Transformations, Type, TypeFunctions, Types, Urls, alias, binary, buildPathAndQuery, createSyncLoader, duration, encode, functions, isQueryCustomType, isRawType, normalizeValue, operators, pathAndParamsFromQueryOptions, pathAndParamsFromSegments, provideODataClient, raw, render, resolve, syntax, transformations };
14260
14396
  //# sourceMappingURL=angular-odata.mjs.map