@sap/cds 6.0.2 → 6.1.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/CHANGELOG.md +153 -19
- package/apis/cds.d.ts +11 -7
- package/apis/log.d.ts +48 -0
- package/apis/ql.d.ts +72 -15
- package/bin/build/buildTaskHandler.js +5 -2
- package/bin/build/constants.js +4 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +11 -39
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +13 -32
- package/bin/build/provider/buildTaskHandlerInternal.js +56 -4
- package/bin/build/provider/buildTaskProviderInternal.js +22 -14
- package/bin/build/provider/hana/index.js +8 -7
- package/bin/build/provider/java/index.js +18 -8
- package/bin/build/provider/mtx/index.js +7 -4
- package/bin/build/provider/mtx/resourcesTarBuilder.js +64 -35
- package/bin/build/provider/mtx-extension/index.js +57 -0
- package/bin/build/provider/mtx-sidecar/index.js +46 -18
- package/bin/build/provider/nodejs/index.js +34 -13
- package/bin/build/util.js +6 -4
- package/bin/deploy/to-hana/cfUtil.js +7 -2
- package/bin/deploy/to-hana/hana.js +6 -3
- package/bin/serve.js +8 -13
- package/lib/compile/{index.js → cds-compile.js} +0 -0
- package/lib/compile/extend.js +15 -5
- package/lib/compile/minify.js +1 -15
- package/lib/compile/parse.js +1 -1
- package/lib/compile/resolve.js +2 -2
- package/lib/compile/to/srvinfo.js +6 -4
- package/lib/{deploy.js → dbs/cds-deploy.js} +8 -8
- package/lib/env/{index.js → cds-env.js} +1 -17
- package/lib/env/{requires.js → cds-requires.js} +24 -3
- package/lib/env/defaults.js +7 -1
- package/lib/env/schemas/cds-package.json +11 -0
- package/lib/env/schemas/cds-rc.json +605 -0
- package/lib/index.js +20 -17
- package/lib/log/{errors.js → cds-error.js} +1 -1
- package/lib/log/{index.js → cds-log.js} +0 -0
- package/lib/ql/SELECT.js +1 -1
- package/lib/ql/{index.js → cds-ql.js} +0 -0
- package/lib/req/cds-context.js +1 -1
- package/lib/req/context.js +35 -7
- package/lib/req/locale.js +5 -1
- package/lib/{serve → srv}/adapters.js +23 -19
- package/lib/{connect → srv}/bindings.js +0 -0
- package/lib/{connect/index.js → srv/cds-connect.js} +1 -1
- package/lib/{serve/index.js → srv/cds-serve.js} +1 -1
- package/lib/{serve → srv}/factory.js +2 -3
- package/lib/{serve/Service-api.js → srv/srv-api.js} +14 -6
- package/lib/{serve/Service-dispatch.js → srv/srv-dispatch.js} +3 -2
- package/lib/{serve/Service-handlers.js → srv/srv-handlers.js} +10 -0
- package/lib/{serve/Service-methods.js → srv/srv-methods.js} +10 -8
- package/lib/srv/srv-models.js +206 -0
- package/lib/{serve/Transaction.js → srv/srv-tx.js} +6 -1
- package/lib/utils/{tests.js → cds-test.js} +2 -2
- package/lib/utils/cds-utils.js +146 -0
- package/lib/utils/index.js +2 -136
- package/lib/utils/jest.js +43 -0
- package/lib/utils/resources/index.js +14 -24
- package/lib/utils/resources/tar.js +18 -41
- package/libx/_runtime/auth/index.js +13 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +9 -20
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +19 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +8 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +6 -19
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +8 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +38 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -5
- package/libx/_runtime/cds-services/services/utils/differ.js +4 -0
- package/libx/_runtime/cds-services/util/errors.js +1 -29
- package/libx/_runtime/common/constants/events.js +1 -3
- package/libx/_runtime/common/i18n/messages.properties +2 -1
- package/libx/_runtime/common/perf/index.js +10 -15
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +0 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +8 -5
- package/libx/_runtime/common/utils/template.js +1 -1
- package/libx/_runtime/db/Service.js +2 -14
- package/libx/_runtime/db/expand/expandCQNToJoin.js +28 -25
- package/libx/_runtime/db/generic/input.js +4 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +37 -18
- package/libx/_runtime/extensibility/activate.js +47 -47
- package/libx/_runtime/extensibility/add.js +19 -13
- package/libx/_runtime/extensibility/addExtension.js +17 -13
- package/libx/_runtime/extensibility/defaults.js +25 -30
- package/libx/_runtime/extensibility/linter/allowlist_checker.js +373 -0
- package/libx/_runtime/extensibility/linter/annotations_checker.js +113 -0
- package/libx/_runtime/extensibility/linter/checker_base.js +20 -0
- package/libx/_runtime/extensibility/linter/namespace_checker.js +180 -0
- package/libx/_runtime/extensibility/linter.js +32 -0
- package/libx/_runtime/extensibility/push.js +78 -21
- package/libx/_runtime/extensibility/service.js +29 -12
- package/libx/_runtime/extensibility/token.js +56 -0
- package/libx/_runtime/extensibility/validation.js +6 -9
- package/libx/_runtime/fiori/generic/activate.js +0 -4
- package/libx/_runtime/fiori/generic/edit.js +1 -9
- package/libx/_runtime/fiori/generic/new.js +3 -28
- package/libx/_runtime/fiori/generic/patch.js +6 -7
- package/libx/_runtime/fiori/generic/prepare.js +11 -18
- package/libx/_runtime/fiori/generic/read.js +11 -1
- package/libx/_runtime/fiori/utils/handler.js +0 -17
- package/libx/_runtime/hana/Service.js +0 -1
- package/libx/_runtime/hana/conversion.js +12 -1
- package/libx/_runtime/hana/customBuilder/CustomFunctionBuilder.js +4 -3
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +5 -0
- package/libx/_runtime/hana/pool.js +6 -10
- package/libx/_runtime/hana/search2Contains.js +0 -5
- package/libx/_runtime/hana/search2cqn4sql.js +1 -0
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +18 -19
- package/libx/_runtime/messaging/file-based.js +1 -0
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/service.js +11 -6
- package/libx/_runtime/remote/utils/client.js +6 -2
- package/libx/_runtime/remote/utils/data.js +5 -0
- package/libx/_runtime/sqlite/Service.js +0 -1
- package/libx/odata/afterburner.js +79 -2
- package/libx/odata/cqn2odata.js +9 -7
- package/libx/odata/grammar.pegjs +161 -77
- package/libx/odata/index.js +9 -3
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +39 -5
- package/libx/rest/RestAdapter.js +1 -2
- package/libx/rest/middleware/delete.js +4 -5
- package/libx/rest/middleware/parse.js +3 -2
- package/package.json +3 -3
- package/server.js +1 -1
- package/srv/extensibility-service.cds +6 -3
- package/srv/model-provider.cds +3 -1
- package/srv/model-provider.js +84 -104
- package/srv/mtx.js +7 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +0 -240
package/libx/odata/grammar.pegjs
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
//
|
|
28
28
|
// ---------- JavaScript Helpers -------------
|
|
29
29
|
{
|
|
30
|
+
|
|
30
31
|
const $ = Object.assign
|
|
31
32
|
const { strict, minimal } = options
|
|
32
33
|
const stack = []
|
|
@@ -243,7 +244,7 @@
|
|
|
243
244
|
|
|
244
245
|
ODataRelativeURI // Note: case-sensitive!
|
|
245
246
|
= '/'? (p:path { SELECT = p })
|
|
246
|
-
( o"?"o QueryOption ( o'&'o QueryOption )*
|
|
247
|
+
( o"?"o (QueryOption ( o'&'o QueryOption )*)? )? o {
|
|
247
248
|
if (count) {
|
|
248
249
|
// columns set because of $count: ignore $select, $expand, $top, $skip, $orderby
|
|
249
250
|
// REVISIT: don't ignore query options but throw bad request (as okra did)?
|
|
@@ -334,46 +335,39 @@
|
|
|
334
335
|
QueryOption = option:ExpandOption { if(option && option.apply) SELECT.apply = option.apply} /
|
|
335
336
|
"$skiptoken=" o skiptoken /
|
|
336
337
|
format /
|
|
337
|
-
custom
|
|
338
|
+
custom /
|
|
339
|
+
aliasedParamEqualsVal
|
|
338
340
|
// @OData spec for $expand:
|
|
339
341
|
// "Allowed system query options are $filter, $select, $orderby, $skip, $top, $count, $search, $expand and $apply (http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs02/odata-data-aggregation-ext-v4.0-cs02.html#_The_expand_Transformation)."
|
|
340
342
|
ExpandOption =
|
|
341
343
|
"$select=" o select ( COMMA select )* /
|
|
342
|
-
"$expand=" o expand ( COMMA expand )* /
|
|
343
|
-
"$filter=" o f:filter{SELECT.where = f} /
|
|
344
|
+
"$expand=" o expand ( COMMA expand )* expandCount? /
|
|
345
|
+
"$filter=" o f:filter { SELECT.where = f } /
|
|
344
346
|
"$orderby=" o o:orderby ( COMMA o2:orderby{_setOrderBy(o2)} )* {_setOrderBy(o,true)} /
|
|
345
|
-
"$top=" o val:top{(SELECT.limit || (SELECT.limit={})).rows = {val}} /
|
|
346
|
-
"$skip=" o val:skip{_setLimitOffset(val)} /
|
|
347
|
-
"$search=" o s:search {if (s) SELECT.search = s} /
|
|
347
|
+
"$top=" o val:top { (SELECT.limit || (SELECT.limit={})).rows = {val} } /
|
|
348
|
+
"$skip=" o val:skip { _setLimitOffset(val) } /
|
|
349
|
+
"$search=" o s:search { if (s) SELECT.search = s } /
|
|
348
350
|
"$count=" o count /
|
|
349
|
-
"$apply=" o trafos:transformations {return trafos}
|
|
351
|
+
"$apply=" o trafos:transformations { return trafos }
|
|
350
352
|
|
|
351
353
|
|
|
352
354
|
select
|
|
353
|
-
= col:('*'/ref) {
|
|
355
|
+
= col:('*' / ref) {
|
|
354
356
|
SELECT.columns = Array.isArray(SELECT.columns) ? SELECT.columns : []
|
|
355
357
|
if (!SELECT.columns.find(_compareRefs(col))) SELECT.columns.push(col)
|
|
356
358
|
return col
|
|
357
359
|
}
|
|
358
360
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
)
|
|
370
|
-
( // --- nested query options, if any
|
|
371
|
-
(OPEN {
|
|
372
|
-
stack.push (SELECT)
|
|
373
|
-
SELECT = SELECT.expand[SELECT.expand.length-1]
|
|
374
|
-
SELECT.expand = '*' // by default expand everything
|
|
375
|
-
})(
|
|
376
|
-
expandOptions:( o ";"? o option:ExpandOption{return option})*
|
|
361
|
+
expandCount
|
|
362
|
+
= "/$count" {
|
|
363
|
+
const err = new Error("EXPAND_COUNT_UNSUPPORTED");
|
|
364
|
+
err.statusCode=501;
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
expandQueryOptions
|
|
369
|
+
= (
|
|
370
|
+
expandOptions:(option:ExpandOption o ";"? { return option })*
|
|
377
371
|
{
|
|
378
372
|
if (expandOptions.find(option => option && option.apply !== undefined)) {
|
|
379
373
|
const err = new Error("EXPAND_APPLY_UNSUPPORTED");
|
|
@@ -390,29 +384,50 @@
|
|
|
390
384
|
if (Array.isArray(SELECT.expand) && SELECT.expand.indexOf('*') === -1) SELECT.expand.unshift('*')
|
|
391
385
|
}
|
|
392
386
|
}
|
|
393
|
-
)
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
expandQueryOption
|
|
390
|
+
= (OPEN {
|
|
391
|
+
stack.push (SELECT)
|
|
392
|
+
SELECT = SELECT.expand[SELECT.expand.length-1]
|
|
393
|
+
SELECT.expand = '*' // by default expand everything
|
|
394
|
+
})
|
|
395
|
+
expandQueryOptions?
|
|
396
|
+
(CLOSE {
|
|
394
397
|
SELECT = stack.pop()
|
|
395
398
|
})
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
//REVISIT: per OData spec $apply should be also supported inside of $expand
|
|
402
|
+
expand
|
|
403
|
+
= (
|
|
404
|
+
c:('*' / ref) {
|
|
405
|
+
const col = c === '*' ? {} : c
|
|
406
|
+
col.expand = '*'
|
|
407
|
+
if (!Array.isArray(SELECT.expand)) SELECT.expand = []
|
|
408
|
+
if (!SELECT.expand.find(_compareRefs(col))) SELECT.expand.push(col)
|
|
409
|
+
return col
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
expandQueryOption?
|
|
413
|
+
|
|
403
414
|
top
|
|
404
|
-
= val:integer {return val}
|
|
415
|
+
= val:integer { return val }
|
|
416
|
+
|
|
405
417
|
skiptoken
|
|
406
418
|
= val:integer? skiptoken:skiptokenChars? {
|
|
407
419
|
// REVISIT ignore non-numeric $skiptoken as not supported by CQN
|
|
408
420
|
if (skiptoken) return
|
|
409
421
|
_setLimitOffset(val)
|
|
410
422
|
}
|
|
423
|
+
|
|
411
424
|
skip
|
|
412
|
-
= val:integer {return val}
|
|
425
|
+
= val:integer { return val }
|
|
426
|
+
|
|
413
427
|
search
|
|
414
428
|
= p:search_clause {return p}
|
|
415
429
|
/ o // Do not add search property for space only
|
|
430
|
+
|
|
416
431
|
search_clause
|
|
417
432
|
= p:( n:NOT? {return n?[n]:[]} )(
|
|
418
433
|
OPEN xpr:search_clause CLOSE {p.push({xpr})}
|
|
@@ -422,9 +437,11 @@
|
|
|
422
437
|
val:word {p.push({val})}
|
|
423
438
|
)
|
|
424
439
|
)( ao:(AND/OR/AND_SPACE) more:search_clause {p.push(ao,...more)} )*
|
|
425
|
-
{return p}
|
|
440
|
+
{ return p }
|
|
441
|
+
|
|
426
442
|
filter
|
|
427
443
|
= p:where_clause { return p }
|
|
444
|
+
|
|
428
445
|
where_clause = p:( n:NOT? {return n?[n]:[]} )(
|
|
429
446
|
OPEN xpr:where_clause CLOSE {p.push({xpr})}
|
|
430
447
|
/ comp:comparison {p.push(...comp)}
|
|
@@ -437,8 +454,10 @@
|
|
|
437
454
|
}
|
|
438
455
|
/ func:boolish {p.push(func)}
|
|
439
456
|
/ val:bool {p.push({val})}
|
|
457
|
+
/ list:listFilter {p.push(...list)}
|
|
440
458
|
)( ao:(AND/OR) more:where_clause {p.push(ao,...more)} )*
|
|
441
|
-
{return p}
|
|
459
|
+
{ return p }
|
|
460
|
+
|
|
442
461
|
lambda =
|
|
443
462
|
nav:( n:identifier {return[n]} ) '/' ( n:identifier '/' {nav.push(n)} )*
|
|
444
463
|
xpr:(
|
|
@@ -467,28 +486,48 @@
|
|
|
467
486
|
}
|
|
468
487
|
)
|
|
469
488
|
{ return xpr }
|
|
489
|
+
|
|
470
490
|
inner_lambda =
|
|
471
491
|
p:( n:NOT? { return n ? [n] : [] } )(
|
|
472
492
|
OPEN xpr:inner_lambda CLOSE { p.push('(', ...xpr, ')') }
|
|
473
493
|
/ comp:comparison { p.push(...comp) }
|
|
474
494
|
/ func:function { p.push(func) }
|
|
475
495
|
/ lambda:lambda { p.push(...lambda)}
|
|
496
|
+
/ list:listFilter {p.push(...list)}
|
|
476
497
|
)
|
|
477
498
|
( ao:(AND/OR) more:inner_lambda { p.push(ao, ...more) } )*
|
|
478
499
|
{ return p }
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
500
|
+
|
|
501
|
+
lambda_clause =
|
|
502
|
+
prefix:identifier ":" inner:inner_lambda {
|
|
503
|
+
return _removeLambdaPrefix(prefix, inner)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
any =
|
|
507
|
+
"any" OPEN p:lambda_clause? CLOSE { return p }
|
|
508
|
+
|
|
509
|
+
all =
|
|
510
|
+
"all" OPEN p:lambda_clause CLOSE { return p }
|
|
511
|
+
|
|
484
512
|
orderby
|
|
485
|
-
= ref:(
|
|
513
|
+
= ref:(
|
|
514
|
+
lambda {
|
|
515
|
+
const err = new Error("ORDERBY_LAMBDA_UNSUPPORTED");
|
|
516
|
+
err.statusCode=501;
|
|
517
|
+
throw err;
|
|
518
|
+
} /
|
|
519
|
+
function /
|
|
520
|
+
ref
|
|
521
|
+
)
|
|
522
|
+
sort:( _ s:$("asc" / "desc") { return s })? {
|
|
486
523
|
// TODO: Lambda support
|
|
487
524
|
const appendObj = $(ref, sort && {sort});
|
|
488
525
|
return appendObj;
|
|
489
526
|
}
|
|
527
|
+
|
|
490
528
|
count
|
|
491
529
|
= val:bool { if(val) SELECT.count = true }
|
|
530
|
+
|
|
492
531
|
transformations
|
|
493
532
|
= mainTransformation:trafo additionalTransformation:("/" t2:trafo {
|
|
494
533
|
return t2
|
|
@@ -520,7 +559,12 @@
|
|
|
520
559
|
}
|
|
521
560
|
return {apply: mainTransformation}
|
|
522
561
|
}
|
|
523
|
-
|
|
562
|
+
|
|
563
|
+
custom
|
|
564
|
+
= [a-zA-Z0-9-_.~]+ "=" [^&]*
|
|
565
|
+
aliasedParam "an aliased parameter (@param)" = "@" i:identifier { return "@" + i }
|
|
566
|
+
aliasedParamEqualsVal "@alias=value" = a:aliasedParam "=" v:([^&]*) {return a + "=" + v}
|
|
567
|
+
|
|
524
568
|
format = "$format=" f:$([^&]*) {
|
|
525
569
|
if (f.toLowerCase() !== "json") {
|
|
526
570
|
const err = new Error("ONLY_QUERY_PARAM_FORMAT_JSON_ALLOWED")
|
|
@@ -528,17 +572,25 @@
|
|
|
528
572
|
throw err;
|
|
529
573
|
}
|
|
530
574
|
}
|
|
575
|
+
|
|
531
576
|
//
|
|
532
577
|
// ---------- Expressions ------------
|
|
533
|
-
comparison
|
|
534
|
-
= a:operand _ o:$("eq"/"ne"/"lt"/"gt"/"le"/"ge") _ b:operand {
|
|
535
|
-
const op = { eq:'=', ne:'!=', lt:'<', gt:'>', le:'<=', ge:'>=' }[o]||o
|
|
578
|
+
comparison
|
|
579
|
+
= a:operand _ o:$("eq" / "ne" / "lt" / "gt" / "le" / "ge") _ b:operand {
|
|
580
|
+
const op = { eq:'=', ne:'!=', lt:'<', gt:'>', le:'<=', ge:'>=' }[o] || o
|
|
536
581
|
return [ a, op, b ]
|
|
537
582
|
}
|
|
583
|
+
|
|
584
|
+
listFilter
|
|
585
|
+
= a:operand _ "in" _ b:listRoundBrackets {
|
|
586
|
+
return [ a, "in", b ]
|
|
587
|
+
}
|
|
538
588
|
mathCalc
|
|
539
589
|
= operand (_ ("add" / "sub" / "mul" / "div" / "mod") _ operand)*
|
|
540
|
-
|
|
590
|
+
|
|
591
|
+
operand
|
|
541
592
|
= navigationCount / function / val / ref / jsonObject / jsonArray / list
|
|
593
|
+
|
|
542
594
|
navigationCount "navigation with $count"
|
|
543
595
|
= navigationPath:(head:identifier key:(OPEN keyArgs:args CLOSE {return keyArgs;})? '/' {
|
|
544
596
|
if (key) {
|
|
@@ -548,6 +600,7 @@
|
|
|
548
600
|
return head;
|
|
549
601
|
})+ count: '$count'
|
|
550
602
|
{ return {func: 'count', as: '$count', args: [{ref: navigationPath}]} }
|
|
603
|
+
|
|
551
604
|
ref "a reference"
|
|
552
605
|
= head:identifier tail:( '/' n:identifier {return n})*
|
|
553
606
|
{
|
|
@@ -556,34 +609,56 @@
|
|
|
556
609
|
}
|
|
557
610
|
return { ref:[ head, ...tail ] }
|
|
558
611
|
}
|
|
612
|
+
|
|
559
613
|
val
|
|
560
614
|
= val:(bool / date) {return {val}}
|
|
561
615
|
/ val:guid {return {val}}
|
|
562
616
|
/ val:number {return typeof val === 'number' ? {val} : { val, literal:'number' }}
|
|
563
617
|
/ val:string {return {val}}
|
|
564
618
|
/ val:binary {return {val}}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
619
|
+
/ val:aliasedParam {return {val}}
|
|
620
|
+
/ null
|
|
621
|
+
|
|
622
|
+
null "null" = "null" {return {val: null }}
|
|
623
|
+
|
|
624
|
+
jsonObject "a json object"
|
|
625
|
+
= val:$("{" (jsonObject / [^}])* "}") {return {val}}
|
|
626
|
+
|
|
627
|
+
jsonArray "a json array"
|
|
628
|
+
= val:$("[" o "]" / "[" o "{" (jsonArray / [^\]])* "]") {return {val}}
|
|
629
|
+
|
|
630
|
+
list "a list"
|
|
569
631
|
= "[" any:$([^\]])* "]" // > needs improvment
|
|
570
632
|
{ return { list: any.replace(/"/g,'').split(',').map(ele => ({ val: ele })) } }
|
|
571
633
|
|
|
572
|
-
|
|
573
|
-
=
|
|
634
|
+
listRoundBrackets "a list"
|
|
635
|
+
= OPEN list:(val1:val val2:("," v:val { return v })* { return [val1, ...val2] }) CLOSE // > needs improvment
|
|
636
|
+
{
|
|
637
|
+
return { list }
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
functionName "a function name"
|
|
642
|
+
= $[a-zA-Z]+
|
|
643
|
+
|
|
644
|
+
function
|
|
645
|
+
= func:functionName OPEN fnArgs:functionArgs CLOSE {
|
|
574
646
|
if (strict && !(func.toLowerCase() in strict.functions)) {
|
|
575
647
|
throw Object.assign(new Error(`"${func}" is an unknown function in OData URL spec (strict mode)`), { statusCode: 400 })
|
|
576
648
|
}
|
|
577
|
-
return { func: func.toLowerCase(), args:[a,...more] }
|
|
649
|
+
return { func: func.toLowerCase(), args:[fnArgs.a,...fnArgs.more] }
|
|
578
650
|
}
|
|
579
651
|
|
|
580
|
-
|
|
652
|
+
functionArgs
|
|
653
|
+
= a:operand more:( COMMA o:operand {return o} )* {return { a, more }}
|
|
654
|
+
|
|
655
|
+
boolish
|
|
581
656
|
= func:("contains"i/"endswith"i/"startswith"i) OPEN a:operand COMMA b:operand CLOSE
|
|
582
657
|
{ return { func: func.toLowerCase(), args:[a,b] }}
|
|
583
658
|
|
|
584
659
|
NOT = o "NOT"i _ {return 'not'}
|
|
585
660
|
AND = _ "AND"i _ {return 'and'}
|
|
586
|
-
AND_SPACE =
|
|
661
|
+
AND_SPACE = _ {return 'and'}
|
|
587
662
|
OR = _ "OR"i _ {return 'or'}
|
|
588
663
|
|
|
589
664
|
|
|
@@ -619,7 +694,7 @@
|
|
|
619
694
|
}
|
|
620
695
|
return {aggregate: [{ func, args }]}
|
|
621
696
|
} /
|
|
622
|
-
identity: identityTrafo{return identity}
|
|
697
|
+
identity: identityTrafo {return identity}
|
|
623
698
|
// customFunction
|
|
624
699
|
)
|
|
625
700
|
|
|
@@ -660,7 +735,11 @@
|
|
|
660
735
|
groupByElem
|
|
661
736
|
= c:(rollupSpec / ref) { return c }
|
|
662
737
|
rollupSpec // TODO fix this + add CAP support
|
|
663
|
-
= rollup:("rollup" OPEN o ('$all' / ref) (o COMMA ref)+ o CLOSE) {
|
|
738
|
+
= rollup:("rollup" OPEN o ('$all' / ref) (o COMMA ref)+ o CLOSE) {
|
|
739
|
+
const err = new Error("Rollup in groupby is not supported yet.");
|
|
740
|
+
err.statusCode=501;
|
|
741
|
+
throw err;
|
|
742
|
+
}
|
|
664
743
|
|
|
665
744
|
filterTrafo = OPEN o where:(where:filter{
|
|
666
745
|
return where
|
|
@@ -704,20 +783,21 @@
|
|
|
704
783
|
//
|
|
705
784
|
// ---------- Literals -----------
|
|
706
785
|
|
|
707
|
-
bool
|
|
786
|
+
bool "a boolean"
|
|
787
|
+
= b:("true" / "false") { return b === 'true'}
|
|
708
788
|
|
|
709
|
-
string "Edm.String"
|
|
710
|
-
= "'" s:$("''"/[^'])* "'"
|
|
789
|
+
string "a single quoted string" // "Edm.String"
|
|
790
|
+
= "'" s:$("''" / [^'])* "'" // 'A user''s story'
|
|
711
791
|
{return s.replace(/''/g,"'")}
|
|
712
792
|
|
|
713
|
-
doubleQuotedString
|
|
793
|
+
doubleQuotedString "a doubled quoted string"
|
|
714
794
|
= '"' s:$('\\"'/[^"])* '"'
|
|
715
795
|
{return s.replace(/\\\\/g,"\\").replace(/\\"/g,'"')}
|
|
716
796
|
|
|
717
|
-
word
|
|
797
|
+
word "a string"
|
|
718
798
|
= $([^ \t\n()"&;]+)
|
|
719
799
|
|
|
720
|
-
date
|
|
800
|
+
date "a date"
|
|
721
801
|
= s:$( [0-9]+"-"[0-9][0-9]"-"[0-9][0-9] // date
|
|
722
802
|
( "T"[0-9][0-9]":"[0-9][0-9](":"[0-9][0-9]("."[0-9]+)?)? // time
|
|
723
803
|
( "Z" / (("+" / "-")[0-9][0-9]":"[0-9][0-9]) )? // timezone (Z or +-hh:mm)
|
|
@@ -727,19 +807,23 @@
|
|
|
727
807
|
return s
|
|
728
808
|
}
|
|
729
809
|
|
|
730
|
-
number
|
|
731
|
-
|
|
810
|
+
// to avoid 123-123-123 being matched as number and showing error for "-123-123"
|
|
811
|
+
endsWithMinus
|
|
812
|
+
= [0-9]+ "-"
|
|
813
|
+
|
|
814
|
+
number "a number"
|
|
815
|
+
= !endsWithMinus s:$( [+-]? [0-9]+ ("."[0-9]+)? ("e"[0-9]+)? ) { return safeNumber(s) }
|
|
732
816
|
|
|
733
|
-
integer
|
|
817
|
+
integer "an integer"
|
|
734
818
|
= s:$( [+-]? [0-9]+ ) { return parseInt(s) }
|
|
735
819
|
|
|
736
|
-
identifier
|
|
820
|
+
identifier "an identifier"
|
|
737
821
|
= !bool !guid s:$([_a-zA-Z][_a-zA-Z0-9"."]*) { return s }
|
|
738
822
|
|
|
739
|
-
guid
|
|
823
|
+
guid "a guid"
|
|
740
824
|
= $( hex16 hex16 "-"? hex16 "-"? hex16 "-"? hex16 "-"? hex16 hex16 hex16 )
|
|
741
825
|
|
|
742
|
-
hex16
|
|
826
|
+
hex16 "a hex value"
|
|
743
827
|
= $( [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] )
|
|
744
828
|
|
|
745
829
|
segment // > everything except / and ?
|
|
@@ -748,7 +832,7 @@
|
|
|
748
832
|
skiptokenChars
|
|
749
833
|
= $( [a-zA-Z0-9-"."_~!$'()*+,;=:@"/""?"]+ )
|
|
750
834
|
|
|
751
|
-
binary // > url-safe base64
|
|
835
|
+
binary "a binary" // > url-safe base64
|
|
752
836
|
= "binary'" s:$([a-zA-Z0-9-_]+ ("=="/"=")?) "'" { return standardBase64(s) }
|
|
753
837
|
|
|
754
838
|
//
|
|
@@ -763,8 +847,8 @@
|
|
|
763
847
|
//
|
|
764
848
|
// ---------- Whitespaces -----------
|
|
765
849
|
|
|
766
|
-
o "optional
|
|
767
|
-
_ "
|
|
850
|
+
o "an optional whitespace" = $[ \t\n]*
|
|
851
|
+
_ "a whitespace" = $[ \t\n]+
|
|
768
852
|
|
|
769
853
|
//
|
|
770
|
-
// ------------------------------------
|
|
854
|
+
// ------------------------------------
|
package/libx/odata/index.js
CHANGED
|
@@ -74,12 +74,18 @@ module.exports = {
|
|
|
74
74
|
try {
|
|
75
75
|
cqn = odata2cqn(url, options)
|
|
76
76
|
} catch (err) {
|
|
77
|
-
if (err.
|
|
78
|
-
throw getError(err.statusCode
|
|
77
|
+
if (err.statusCode === 501) {
|
|
78
|
+
throw getError(err.statusCode, err.message)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let offset = err.location && err.location.start.offset
|
|
82
|
+
if (options.baseUrl) {
|
|
83
|
+
// we need to add the number of chars from base url to the offset
|
|
84
|
+
offset += options.baseUrl.length
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
// TODO adjust this to behave like above
|
|
82
|
-
err.message =
|
|
88
|
+
err.message = `Parsing URL failed at position ${offset}: ${err.message}`
|
|
83
89
|
err.statusCode = err.statusCode || 400
|
|
84
90
|
throw err
|
|
85
91
|
}
|