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.
- package/fesm2022/angular-odata.mjs +2298 -2162
- package/fesm2022/angular-odata.mjs.map +1 -1
- package/lib/api.d.ts +10 -11
- package/lib/cache/cache.d.ts +2 -2
- package/lib/cache/memory.d.ts +2 -2
- package/lib/cache/storage.d.ts +2 -2
- package/lib/loaders.d.ts +8 -8
- package/lib/metadata/csdl/csdl-annotation.d.ts +3 -3
- package/lib/metadata/csdl/csdl-entity-container.d.ts +2 -2
- package/lib/metadata/csdl/csdl-entity-set.d.ts +2 -2
- package/lib/metadata/csdl/csdl-enum-type.d.ts +3 -3
- package/lib/metadata/csdl/csdl-function-action.d.ts +4 -4
- package/lib/metadata/csdl/csdl-reference.d.ts +2 -2
- package/lib/metadata/csdl/csdl-schema.d.ts +2 -2
- package/lib/metadata/csdl/csdl-structural-property.d.ts +3 -3
- package/lib/metadata/csdl/csdl-structured-type.d.ts +3 -3
- package/lib/metadata/metadata.d.ts +2 -2
- package/lib/models/options.d.ts +2 -2
- package/lib/module.d.ts +3 -3
- package/lib/options.d.ts +3 -3
- package/lib/resources/query/expressions/apply.d.ts +1 -1
- package/lib/resources/query/expressions/compute.d.ts +1 -1
- package/lib/resources/query/expressions/count.d.ts +1 -1
- package/lib/resources/query/expressions/expand.d.ts +4 -3
- package/lib/resources/query/expressions/filter.d.ts +2 -1
- package/lib/resources/query/expressions/orderby.d.ts +2 -1
- package/lib/resources/query/expressions/search.d.ts +2 -1
- package/lib/resources/query/expressions/select.d.ts +2 -1
- package/lib/resources/query/handlers.d.ts +17 -5
- package/lib/resources/resource.d.ts +5 -5
- package/lib/resources/types/action.d.ts +2 -2
- package/lib/resources/types/entity-set.d.ts +2 -2
- package/lib/resources/types/navigation-property.d.ts +2 -2
- package/lib/resources/types/property.d.ts +2 -2
- package/lib/schema/annotation.d.ts +3 -3
- package/lib/schema/callable.d.ts +3 -3
- package/lib/schema/element.d.ts +3 -3
- package/lib/schema/entity-container.d.ts +2 -2
- package/lib/schema/entity-set.d.ts +2 -2
- package/lib/schema/enum-type.d.ts +2 -2
- package/lib/schema/parsers/callable.d.ts +4 -4
- package/lib/schema/parsers/enum-type.d.ts +3 -3
- package/lib/schema/parsers/structured-type.d.ts +4 -4
- package/lib/schema/schema.d.ts +3 -3
- package/lib/schema/singleton.d.ts +2 -2
- package/lib/schema/structured-type.d.ts +3 -3
- package/lib/services/entity.d.ts +1 -1
- package/lib/settings.d.ts +2 -2
- package/lib/types.d.ts +76 -74
- package/lib/utils/odata.d.ts +2 -2
- package/package.json +3 -5
- package/schematics/apigen/files/api-config/__fileName__.ts +4 -4
- package/esm2022/angular-odata.mjs +0 -5
- package/esm2022/lib/annotations.mjs +0 -146
- package/esm2022/lib/api.mjs +0 -439
- package/esm2022/lib/cache/cache.mjs +0 -177
- package/esm2022/lib/cache/index.mjs +0 -4
- package/esm2022/lib/cache/memory.mjs +0 -30
- package/esm2022/lib/cache/storage.mjs +0 -57
- package/esm2022/lib/client.mjs +0 -215
- package/esm2022/lib/constants.mjs +0 -95
- package/esm2022/lib/helper.mjs +0 -288
- package/esm2022/lib/index.mjs +0 -22
- package/esm2022/lib/loaders.mjs +0 -43
- package/esm2022/lib/metadata/csdl/csdl-annotation.mjs +0 -273
- package/esm2022/lib/metadata/csdl/csdl-entity-container.mjs +0 -59
- package/esm2022/lib/metadata/csdl/csdl-entity-set.mjs +0 -50
- package/esm2022/lib/metadata/csdl/csdl-enum-type.mjs +0 -74
- package/esm2022/lib/metadata/csdl/csdl-function-action.mjs +0 -204
- package/esm2022/lib/metadata/csdl/csdl-navigation-property-binding.mjs +0 -15
- package/esm2022/lib/metadata/csdl/csdl-reference.mjs +0 -76
- package/esm2022/lib/metadata/csdl/csdl-schema.mjs +0 -87
- package/esm2022/lib/metadata/csdl/csdl-singleton.mjs +0 -37
- package/esm2022/lib/metadata/csdl/csdl-structural-property.mjs +0 -145
- package/esm2022/lib/metadata/csdl/csdl-structured-type.mjs +0 -159
- package/esm2022/lib/metadata/csdl/csdl-type-definition.mjs +0 -46
- package/esm2022/lib/metadata/index.mjs +0 -3
- package/esm2022/lib/metadata/metadata.mjs +0 -41
- package/esm2022/lib/metadata/parser.mjs +0 -564
- package/esm2022/lib/models/collection.mjs +0 -816
- package/esm2022/lib/models/index.mjs +0 -4
- package/esm2022/lib/models/model.mjs +0 -577
- package/esm2022/lib/models/options.mjs +0 -1227
- package/esm2022/lib/module.mjs +0 -55
- package/esm2022/lib/options.mjs +0 -91
- package/esm2022/lib/resources/index.mjs +0 -7
- package/esm2022/lib/resources/options.mjs +0 -66
- package/esm2022/lib/resources/path/handlers.mjs +0 -81
- package/esm2022/lib/resources/path/index.mjs +0 -3
- package/esm2022/lib/resources/path/segments.mjs +0 -149
- package/esm2022/lib/resources/query/builder.mjs +0 -645
- package/esm2022/lib/resources/query/expressions/apply.mjs +0 -238
- package/esm2022/lib/resources/query/expressions/base.mjs +0 -26
- package/esm2022/lib/resources/query/expressions/compute.mjs +0 -55
- package/esm2022/lib/resources/query/expressions/count.mjs +0 -118
- package/esm2022/lib/resources/query/expressions/expand.mjs +0 -154
- package/esm2022/lib/resources/query/expressions/filter.mjs +0 -180
- package/esm2022/lib/resources/query/expressions/index.mjs +0 -10
- package/esm2022/lib/resources/query/expressions/orderby.mjs +0 -81
- package/esm2022/lib/resources/query/expressions/search.mjs +0 -144
- package/esm2022/lib/resources/query/expressions/select.mjs +0 -49
- package/esm2022/lib/resources/query/expressions/syntax.mjs +0 -770
- package/esm2022/lib/resources/query/handlers.mjs +0 -423
- package/esm2022/lib/resources/query/index.mjs +0 -5
- package/esm2022/lib/resources/query/options.mjs +0 -140
- package/esm2022/lib/resources/request.mjs +0 -210
- package/esm2022/lib/resources/resource.mjs +0 -316
- package/esm2022/lib/resources/response.mjs +0 -180
- package/esm2022/lib/resources/types/action.mjs +0 -118
- package/esm2022/lib/resources/types/batch.mjs +0 -428
- package/esm2022/lib/resources/types/count.mjs +0 -33
- package/esm2022/lib/resources/types/entity-set.mjs +0 -131
- package/esm2022/lib/resources/types/entity.mjs +0 -112
- package/esm2022/lib/resources/types/function.mjs +0 -149
- package/esm2022/lib/resources/types/index.mjs +0 -15
- package/esm2022/lib/resources/types/media.mjs +0 -44
- package/esm2022/lib/resources/types/metadata.mjs +0 -35
- package/esm2022/lib/resources/types/navigation-property.mjs +0 -246
- package/esm2022/lib/resources/types/options.mjs +0 -2
- package/esm2022/lib/resources/types/property.mjs +0 -187
- package/esm2022/lib/resources/types/reference.mjs +0 -87
- package/esm2022/lib/resources/types/singleton.mjs +0 -125
- package/esm2022/lib/resources/types/value.mjs +0 -48
- package/esm2022/lib/schema/annotation.mjs +0 -44
- package/esm2022/lib/schema/callable.mjs +0 -69
- package/esm2022/lib/schema/element.mjs +0 -70
- package/esm2022/lib/schema/entity-container.mjs +0 -13
- package/esm2022/lib/schema/entity-set.mjs +0 -11
- package/esm2022/lib/schema/enum-type.mjs +0 -69
- package/esm2022/lib/schema/index.mjs +0 -9
- package/esm2022/lib/schema/parsers/callable.mjs +0 -123
- package/esm2022/lib/schema/parsers/edm.mjs +0 -101
- package/esm2022/lib/schema/parsers/enum-type.mjs +0 -148
- package/esm2022/lib/schema/parsers/index.mjs +0 -5
- package/esm2022/lib/schema/parsers/structured-type.mjs +0 -548
- package/esm2022/lib/schema/schema.mjs +0 -52
- package/esm2022/lib/schema/singleton.mjs +0 -11
- package/esm2022/lib/schema/structured-type.mjs +0 -220
- package/esm2022/lib/services/base.mjs +0 -32
- package/esm2022/lib/services/entity-set.mjs +0 -161
- package/esm2022/lib/services/entity.mjs +0 -12
- package/esm2022/lib/services/factory.mjs +0 -39
- package/esm2022/lib/services/index.mjs +0 -5
- package/esm2022/lib/services/singleton.mjs +0 -55
- package/esm2022/lib/settings.mjs +0 -113
- package/esm2022/lib/types.mjs +0 -118
- package/esm2022/lib/utils/arraybuffers.mjs +0 -46
- package/esm2022/lib/utils/arrays.mjs +0 -10
- package/esm2022/lib/utils/dates.mjs +0 -18
- package/esm2022/lib/utils/durations.mjs +0 -40
- package/esm2022/lib/utils/enums.mjs +0 -61
- package/esm2022/lib/utils/http.mjs +0 -95
- package/esm2022/lib/utils/index.mjs +0 -10
- package/esm2022/lib/utils/objects.mjs +0 -204
- package/esm2022/lib/utils/odata.mjs +0 -22
- package/esm2022/lib/utils/strings.mjs +0 -20
- package/esm2022/lib/utils/types.mjs +0 -136
- package/esm2022/lib/utils/urls.mjs +0 -24
- 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 {
|
|
4
|
-
import {
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
1304
|
-
|
|
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
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
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
|
|
252
|
+
return props;
|
|
1369
253
|
},
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
254
|
+
id(annots) {
|
|
255
|
+
return annots instanceof Map
|
|
256
|
+
? annots.get(this.ODATA_ID)
|
|
257
|
+
: annots[this.ODATA_ID];
|
|
1373
258
|
},
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
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
|
-
|
|
1384
|
-
let
|
|
1385
|
-
|
|
1386
|
-
|
|
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
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
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
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
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
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
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
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
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
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
316
|
+
readLink(annots) {
|
|
317
|
+
return annots.has(this.ODATA_READLINK)
|
|
318
|
+
? decodeURIComponent(annots.get(this.ODATA_READLINK))
|
|
319
|
+
: undefined;
|
|
1455
320
|
},
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
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
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
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
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
return
|
|
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
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
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
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
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
|
-
|
|
683
|
+
path += `/${funcName}(${funcArgs})`;
|
|
1592
684
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
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
|
-
|
|
710
|
+
if (builtFilter) {
|
|
711
|
+
acc.push(builtFilter);
|
|
712
|
+
}
|
|
1600
713
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
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
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
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
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
.
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
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
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
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
|
-
|
|
1688
|
-
return
|
|
940
|
+
else if (value instanceof Date) {
|
|
941
|
+
return value.toISOString();
|
|
1689
942
|
}
|
|
1690
|
-
|
|
1691
|
-
return
|
|
943
|
+
else if (typeof value === 'number') {
|
|
944
|
+
return value;
|
|
1692
945
|
}
|
|
1693
|
-
|
|
1694
|
-
return
|
|
946
|
+
else if (Array.isArray(value)) {
|
|
947
|
+
return `[${value
|
|
948
|
+
.map((d) => normalizeValue(d, { aliases, escape }))
|
|
949
|
+
.join(',')}]`;
|
|
1695
950
|
}
|
|
1696
|
-
|
|
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
|
-
|
|
1703
|
-
|
|
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
|
-
|
|
1708
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
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
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
const
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
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
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
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
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
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
|
-
|
|
1773
|
-
|
|
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
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
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
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
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
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
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
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
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
|
-
//
|
|
1820
|
-
const
|
|
1821
|
-
|
|
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
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
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
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
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
|
|
1253
|
+
return [];
|
|
1846
1254
|
},
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
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 (
|
|
1856
|
-
|
|
1261
|
+
if (typeof value === 'string') {
|
|
1262
|
+
value = value.split(',').map((o) => o.trim());
|
|
1857
1263
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
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
|
|
1269
|
+
return [];
|
|
1862
1270
|
},
|
|
1863
1271
|
};
|
|
1864
1272
|
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
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
|
-
|
|
1878
|
-
return
|
|
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
|
-
|
|
1886
|
-
|
|
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
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
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
|
-
|
|
2012
|
-
|
|
2013
|
-
return this._fields.filter((f) => names.includes(f.name));
|
|
1322
|
+
function areDatesEqual() {
|
|
1323
|
+
return value1.getTime() === value2.getTime();
|
|
2014
1324
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
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
|
-
|
|
2040
|
-
|
|
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
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
return
|
|
2053
|
-
|
|
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
|
-
|
|
2057
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2096
|
-
|
|
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
|
-
|
|
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
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
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
|
-
|
|
2115
|
-
|
|
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
|
-
|
|
2118
|
-
|
|
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
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
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
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
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
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
1468
|
+
headerValue(header) {
|
|
1469
|
+
let res = header.split(';')[0].trim();
|
|
1470
|
+
res = res.split(':')[1].trim();
|
|
1471
|
+
return res;
|
|
2143
1472
|
},
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
:
|
|
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
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
return
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
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
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
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
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
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
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
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
|
-
|
|
2177
|
-
const
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
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
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
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
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
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
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
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
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
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
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
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
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
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
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
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
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
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
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
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
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
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
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
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
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
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
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
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
|
|
3601
|
-
this._negated = negated
|
|
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
|
|
3808
|
-
this._negated = negated
|
|
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
|
|
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) &&
|
|
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
|
|
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
|
-
|
|
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: "
|
|
13910
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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: "
|
|
14197
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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: "
|
|
14240
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
14241
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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,
|
|
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
|