@sap/cds-compiler 2.7.0 → 2.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -0
- package/bin/cdsc.js +42 -25
- package/bin/cdsse.js +1 -0
- package/doc/CHANGELOG_BETA.md +10 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +17 -33
- package/lib/api/options.js +25 -13
- package/lib/api/validate.js +33 -9
- package/lib/backends.js +9 -8
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +32 -2
- package/lib/base/message-registry.js +26 -2
- package/lib/base/messages.js +25 -9
- package/lib/base/model.js +5 -3
- package/lib/base/optionProcessorHelper.js +56 -22
- package/lib/checks/onConditions.js +5 -0
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +41 -0
- package/lib/checks/validator.js +7 -2
- package/lib/compiler/assert-consistency.js +18 -5
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +30 -1
- package/lib/compiler/checks.js +5 -2
- package/lib/compiler/definer.js +145 -120
- package/lib/compiler/index.js +16 -4
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +207 -47
- package/lib/compiler/shared.js +47 -200
- package/lib/compiler/utils.js +173 -0
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +94 -98
- package/lib/edm/edm.js +16 -20
- package/lib/edm/edmPreprocessor.js +302 -115
- package/lib/edm/edmUtils.js +31 -12
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +28 -1
- package/lib/gen/language.tokens +79 -69
- package/lib/gen/languageLexer.interp +28 -1
- package/lib/gen/languageLexer.js +879 -805
- package/lib/gen/languageLexer.tokens +71 -62
- package/lib/gen/languageParser.js +5308 -4308
- package/lib/json/from-csn.js +59 -30
- package/lib/json/to-csn.js +354 -105
- package/lib/language/antlrParser.js +11 -0
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +81 -14
- package/lib/language/language.g4 +163 -31
- package/lib/main.d.ts +136 -17
- package/lib/main.js +7 -1
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +115 -32
- package/lib/model/csnUtils.js +71 -33
- package/lib/model/enrichCsn.js +36 -9
- package/lib/model/revealInternalProperties.js +20 -4
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +33 -16
- package/lib/render/.eslintrc.json +3 -1
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/toCdl.js +60 -17
- package/lib/render/toHdbcds.js +122 -74
- package/lib/render/toSql.js +57 -32
- package/lib/render/utils/common.js +6 -10
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/db/constraints.js +273 -119
- package/lib/transform/db/draft.js +9 -6
- package/lib/transform/db/expansion.js +19 -7
- package/lib/transform/db/flattening.js +31 -7
- package/lib/transform/db/transformExists.js +344 -66
- package/lib/transform/db/views.js +438 -0
- package/lib/transform/forHanaNew.js +65 -436
- package/lib/transform/forOdataNew.js +21 -10
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/generateForeignKeyElements.js +11 -10
- package/lib/transform/odata/referenceFlattener.js +44 -38
- package/lib/transform/odata/sortByAssociationDependency.js +2 -2
- package/lib/transform/odata/structuralPath.js +72 -0
- package/lib/transform/odata/structureFlattener.js +13 -10
- package/lib/transform/odata/typesExposure.js +22 -12
- package/lib/transform/transformUtilsNew.js +55 -9
- package/lib/transform/translateAssocsToJoins.js +11 -17
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +5 -3
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
package/lib/compiler/resolver.js
CHANGED
|
@@ -47,25 +47,28 @@ const {
|
|
|
47
47
|
const { dictLocation } = require('../base/location');
|
|
48
48
|
const { searchName, weakLocation } = require('../base/messages');
|
|
49
49
|
const { combinedLocation } = require('../base/location');
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
const { kindProperties } = require('./base');
|
|
51
52
|
const {
|
|
52
|
-
|
|
53
|
+
pushLink,
|
|
54
|
+
setLink,
|
|
53
55
|
augmentPath,
|
|
54
56
|
splitIntoPath,
|
|
55
|
-
|
|
57
|
+
linkToOrigin,
|
|
58
|
+
setMemberParent,
|
|
59
|
+
withAssociation,
|
|
60
|
+
storeExtension,
|
|
61
|
+
dependsOn,
|
|
62
|
+
dependsOnSilent,
|
|
63
|
+
} = require('./utils');
|
|
56
64
|
|
|
57
65
|
const detectCycles = require('./cycle-detector');
|
|
58
66
|
const layers = require('./moduleLayers');
|
|
59
67
|
|
|
60
|
-
const {
|
|
61
|
-
kindProperties, fns, setLink, linkToOrigin, setMemberParent, withAssociation, storeExtension,
|
|
62
|
-
dependsOn, dependsOnSilent,
|
|
63
|
-
} = require('./shared');
|
|
64
|
-
|
|
65
68
|
const annotationPriorities = {
|
|
66
69
|
define: 1, extend: 2, annotate: 2, edmx: 3,
|
|
67
70
|
};
|
|
68
|
-
|
|
71
|
+
const $inferred = Symbol.for('cds.$inferred');
|
|
69
72
|
|
|
70
73
|
// Export function of this file. Resolve type references in augmented CSN
|
|
71
74
|
// `model`. If the model has a property argument `messages`, do not throw
|
|
@@ -73,21 +76,21 @@ const annotationPriorities = {
|
|
|
73
76
|
// that property (should be a vector).
|
|
74
77
|
function resolve( model ) {
|
|
75
78
|
const { options } = model;
|
|
76
|
-
// Get shared
|
|
79
|
+
// Get shared functionality and the message function:
|
|
80
|
+
const {
|
|
81
|
+
info, warning, error, message,
|
|
82
|
+
} = model.$messageFunctions;
|
|
77
83
|
const {
|
|
78
84
|
resolvePath,
|
|
79
85
|
resolveTypeArguments,
|
|
80
86
|
defineAnnotations,
|
|
81
87
|
attachAndEmitValidNames,
|
|
82
|
-
} = fns( model, environment );
|
|
83
|
-
const {
|
|
84
|
-
info, warning, error, message,
|
|
85
|
-
} = model.$messageFunctions;
|
|
86
|
-
const {
|
|
87
88
|
initArtifact,
|
|
88
89
|
lateExtensions,
|
|
89
90
|
projectionAncestor,
|
|
90
|
-
} =
|
|
91
|
+
} = model.$functions;
|
|
92
|
+
model.$volatileFunctions.environment = environment;
|
|
93
|
+
|
|
91
94
|
/** @type {any} may also be a boolean */
|
|
92
95
|
let newAutoExposed = [];
|
|
93
96
|
|
|
@@ -242,6 +245,7 @@ function resolve( model ) {
|
|
|
242
245
|
const chain = [];
|
|
243
246
|
while (art && !('_effectiveType' in art) &&
|
|
244
247
|
(art.type || art._origin || art.value && art.value.path) &&
|
|
248
|
+
// TODO: really stop at art.enum?
|
|
245
249
|
!art.target && !art.enum && !art.elements && !art.items) {
|
|
246
250
|
chain.push( art );
|
|
247
251
|
setProp( art, '_effectiveType', 0 ); // initial setting in case of cycles
|
|
@@ -273,13 +277,17 @@ function resolve( model ) {
|
|
|
273
277
|
// collect the "latest" cardinality (calculate lazyly if necessary)
|
|
274
278
|
let cardinality = art.cardinality ||
|
|
275
279
|
art._effectiveType && (() => getCardinality( art._effectiveType ));
|
|
280
|
+
let prev = art;
|
|
276
281
|
for (const a of chain) {
|
|
277
282
|
if (a.cardinality)
|
|
278
283
|
cardinality = a.cardinality;
|
|
279
284
|
if (a.expand && expandFromColumns( a, art, cardinality ) ||
|
|
280
285
|
art.target && redirectImplicitly( a, art ) ||
|
|
281
|
-
art.elements && expandElements( a, art, eType )
|
|
286
|
+
art.elements && expandElements( a, art, eType ) ||
|
|
287
|
+
art.items && expandItems( a, art, eType ))
|
|
282
288
|
art = a;
|
|
289
|
+
else if (art.enum && expandEnum( a, prev ))
|
|
290
|
+
prev = a; // do not set art - effective type is base
|
|
283
291
|
setProp( a, '_effectiveType', art );
|
|
284
292
|
}
|
|
285
293
|
}
|
|
@@ -405,7 +413,7 @@ function resolve( model ) {
|
|
|
405
413
|
for (const view of resolveChain.reverse()) {
|
|
406
414
|
if (view._status !== '_query' ) { // not already resolved
|
|
407
415
|
setProp( view, '_status', '_query' );
|
|
408
|
-
traverseQueryPost( view.query,
|
|
416
|
+
traverseQueryPost( view.query, null, populateQuery );
|
|
409
417
|
if (view.elements$) // specified elements
|
|
410
418
|
mergeSpecifiedElements( view );
|
|
411
419
|
if (!view.$entity) {
|
|
@@ -494,7 +502,8 @@ function resolve( model ) {
|
|
|
494
502
|
});
|
|
495
503
|
}
|
|
496
504
|
forEachGeneric( { elements: alias.elements }, 'elements', ( elem, name ) => {
|
|
497
|
-
|
|
505
|
+
if (elem.$duplicates !== true)
|
|
506
|
+
dictAddArray( query._combined, name, elem, null ); // not dictAdd()
|
|
498
507
|
});
|
|
499
508
|
}
|
|
500
509
|
}
|
|
@@ -535,13 +544,31 @@ function resolve( model ) {
|
|
|
535
544
|
setMemberParent( key, name, elem ); // TODO: set _block here if not present?
|
|
536
545
|
}
|
|
537
546
|
|
|
547
|
+
function expandItems( art, origin, eType ) {
|
|
548
|
+
if (!enableExpandElements || art.items)
|
|
549
|
+
return false;
|
|
550
|
+
if (isInParents( art, eType )) {
|
|
551
|
+
art.items = 0; // circular
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
const ref = art.type || art.value || art.name;
|
|
555
|
+
const location = ref && ref.location || art.location;
|
|
556
|
+
art.items = { $inferred: 'expand-element', location };
|
|
557
|
+
setProp( art.items, '_outer', art );
|
|
558
|
+
setProp( art.items, '_origin', origin.items );
|
|
559
|
+
if (!art.$expand)
|
|
560
|
+
art.$expand = 'origin'; // if value stays, elements won't appear in CSN
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
|
|
538
564
|
function expandElements( art, struct, eType ) {
|
|
539
565
|
if (!enableExpandElements)
|
|
540
566
|
return false;
|
|
541
567
|
if (art.elements || art.kind === '$tableAlias' ||
|
|
542
568
|
// no element expansions for "non-proper" types like
|
|
543
569
|
// entities (as parameter types) etc:
|
|
544
|
-
struct.kind !== 'type' && struct.kind !== 'element' &&
|
|
570
|
+
struct.kind !== 'type' && struct.kind !== 'element' && struct.kind !== 'param' &&
|
|
571
|
+
!struct._outer)
|
|
545
572
|
return false;
|
|
546
573
|
if (struct.elements === 0 || isInParents( art, eType )) {
|
|
547
574
|
art.elements = 0; // circular
|
|
@@ -560,8 +587,33 @@ function resolve( model ) {
|
|
|
560
587
|
// or should we use orig.location? - TODO: try to find test to see message
|
|
561
588
|
.$inferred = 'expand-element';
|
|
562
589
|
}
|
|
563
|
-
|
|
564
|
-
//
|
|
590
|
+
// Set elements expansion status (the if condition is always true, as no
|
|
591
|
+
// elements expansion will take place on artifact with existing other
|
|
592
|
+
// member property):
|
|
593
|
+
if (!art.$expand)
|
|
594
|
+
art.$expand = 'origin'; // if value stays, elements won't appear in CSN
|
|
595
|
+
// TODO: have some art.elements[SYM.$inferred] = 'expand-element';
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function expandEnum( art, origin ) {
|
|
600
|
+
if (!enableExpandElements || art.enum)
|
|
601
|
+
return false;
|
|
602
|
+
const ref = art.type || art.value || art.name;
|
|
603
|
+
const location = weakLocation( ref && ref.location || art.location );
|
|
604
|
+
art.enum = Object.create(null);
|
|
605
|
+
for (const name in origin.enum) {
|
|
606
|
+
const orig = origin.enum[name];
|
|
607
|
+
linkToOrigin( orig, name, art, 'enum', location, true )
|
|
608
|
+
// or should we use orig.location? - TODO: try to find test to see message
|
|
609
|
+
.$inferred = 'expand-element';
|
|
610
|
+
}
|
|
611
|
+
// Set elements expansion status (the if condition is always true, as no
|
|
612
|
+
// elements expansion will take place on artifact with existing other
|
|
613
|
+
// member property):
|
|
614
|
+
if (!art.$expand)
|
|
615
|
+
art.$expand = 'origin'; // if value stays, elements won't appear in CSN
|
|
616
|
+
art.enum[$inferred] = 'expand-element';
|
|
565
617
|
return true;
|
|
566
618
|
}
|
|
567
619
|
|
|
@@ -587,14 +639,45 @@ function resolve( model ) {
|
|
|
587
639
|
return false;
|
|
588
640
|
}
|
|
589
641
|
|
|
590
|
-
|
|
642
|
+
// About Helper property $expand for faster the XSN-to-CSN transformation
|
|
643
|
+
// - null/undefined: artifact, member, items does not contain expanded members
|
|
644
|
+
// - 'origin': all expanded (sub) elements have no new target/on and no new annotations
|
|
645
|
+
// that value is only on elements, types, and params -> no other members
|
|
646
|
+
// when set, only on elem/art with expanded elements
|
|
647
|
+
// - 'target': all expanded (sub) elements might only have new target/on, but
|
|
648
|
+
// no indivual annotations on any (sub) member
|
|
649
|
+
// when set, traverse all parents where the value has been 'origin' before
|
|
650
|
+
// - 'annotate': at least one inferred (sub) member has an individual annotation,
|
|
651
|
+
// not counting propagated ones; set up to the definition (main artifact)
|
|
652
|
+
// (only set with anno on $inferred elem)
|
|
653
|
+
// Usage according to CSN flavor:
|
|
654
|
+
// - gensrc: do not render inferred elements (including expanded elements),
|
|
655
|
+
// collect annotate statements with value 'annotate'
|
|
656
|
+
// - client: do not render expanded sub elements if artifact/member is no type, has a type,
|
|
657
|
+
// has $expand = 'origin', and all its _origin also have $expand = 'origin'
|
|
658
|
+
// (might sometimes render the elements unnecessarily, which is not wrong)
|
|
659
|
+
// - universal: do not render expanded sub elements if $expand = 'origin'
|
|
660
|
+
function setExpandStatus( elem, status ) {
|
|
661
|
+
// set on element
|
|
591
662
|
while (elem._main) {
|
|
592
663
|
elem = elem._parent;
|
|
593
|
-
if (
|
|
664
|
+
if (elem.$expand !== 'origin')
|
|
594
665
|
return;
|
|
595
|
-
elem.$expand =
|
|
666
|
+
elem.$expand = status; // meaning: expanded, containing assocs
|
|
596
667
|
for (let line = elem.items; line; line = line.items)
|
|
597
|
-
line.$expand =
|
|
668
|
+
line.$expand = status; // to-csn just uses the innermost $expand
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
function setExpandStatusAnnotate( elem, status ) {
|
|
672
|
+
for (;;) {
|
|
673
|
+
if (elem.$expand === status)
|
|
674
|
+
return; // already set
|
|
675
|
+
elem.$expand = status; // meaning: expanded, containing annos
|
|
676
|
+
for (let line = elem.items; line; line = line.items)
|
|
677
|
+
line.$expand = status; // to-csn just uses the innermost $expand
|
|
678
|
+
if (!elem._main)
|
|
679
|
+
return;
|
|
680
|
+
elem = elem._parent;
|
|
598
681
|
}
|
|
599
682
|
}
|
|
600
683
|
|
|
@@ -606,7 +689,7 @@ function resolve( model ) {
|
|
|
606
689
|
// PRE: elem has no target, assoc has target prop
|
|
607
690
|
if (elem.kind === '$tableAlias')
|
|
608
691
|
return false;
|
|
609
|
-
setExpandStatus( elem );
|
|
692
|
+
setExpandStatus( elem, 'target' );
|
|
610
693
|
let target = resolvePath( assoc.target, 'target', assoc );
|
|
611
694
|
// console.log( info( null, [ elem.location, elem ], {target,art:assoc,name:''+assoc.target},
|
|
612
695
|
// 'RED').toString())
|
|
@@ -719,6 +802,7 @@ function resolve( model ) {
|
|
|
719
802
|
const nullScope = {
|
|
720
803
|
kind: 'namespace', name: { absolute: autoScopeName, location }, location,
|
|
721
804
|
};
|
|
805
|
+
model.definitions[autoScopeName] = nullScope;
|
|
722
806
|
initArtifact( nullScope );
|
|
723
807
|
return nullScope;
|
|
724
808
|
}
|
|
@@ -1404,8 +1488,9 @@ function resolve( model ) {
|
|
|
1404
1488
|
}
|
|
1405
1489
|
// Resolve projections/views
|
|
1406
1490
|
// if (art.query)console.log( info( null, [art.query.location,art.query], 'VQ:' ).toString() );
|
|
1407
|
-
|
|
1408
|
-
|
|
1491
|
+
|
|
1492
|
+
if (art.$queries)
|
|
1493
|
+
art.$queries.forEach( resolveQuery );
|
|
1409
1494
|
|
|
1410
1495
|
if (obj.type || obj._origin || obj.value && obj.value.path || obj.elements) // typed artifacts
|
|
1411
1496
|
effectiveType(obj); // set _effectiveType if appropriate, (future?): copy elems if extended
|
|
@@ -1550,14 +1635,28 @@ function resolve( model ) {
|
|
|
1550
1635
|
}
|
|
1551
1636
|
}
|
|
1552
1637
|
if (art && art._annotate) {
|
|
1553
|
-
if (art
|
|
1554
|
-
art
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1638
|
+
if (art.kind === 'action' || art.kind === 'function') {
|
|
1639
|
+
expandParameters( art );
|
|
1640
|
+
if (art.returns)
|
|
1641
|
+
effectiveType( art.returns );
|
|
1642
|
+
}
|
|
1643
|
+
const aor = art.returns || art;
|
|
1644
|
+
const obj = aor.items || aor.targetAspect || aor;
|
|
1645
|
+
// Currently(?), effectiveType() does not calculate the effective type of
|
|
1646
|
+
// its line item:
|
|
1647
|
+
effectiveType( obj );
|
|
1648
|
+
if (art._annotate.elements)
|
|
1649
|
+
setExpandStatusAnnotate( aor, 'annotate' );
|
|
1558
1650
|
annotate( obj, 'element', 'elements', 'enum', art );
|
|
1559
1651
|
annotate( art, 'action', 'actions' );
|
|
1560
1652
|
annotate( art, 'param', 'params' );
|
|
1653
|
+
// const { returns } = art._annotate;
|
|
1654
|
+
// if (returns) {
|
|
1655
|
+
// const dict = returns.elements;
|
|
1656
|
+
// const env = obj.returns && obj.returns.elements || null;
|
|
1657
|
+
// for (const n in dict)
|
|
1658
|
+
// annotateMembers( env && env[n], dict[n], 'elements', n, parent, 'element' );
|
|
1659
|
+
// }
|
|
1561
1660
|
}
|
|
1562
1661
|
return;
|
|
1563
1662
|
|
|
@@ -1575,6 +1674,44 @@ function resolve( model ) {
|
|
|
1575
1674
|
annotateMembers( env && env[n], dict[n], prop, n, parent, kind );
|
|
1576
1675
|
}
|
|
1577
1676
|
}
|
|
1677
|
+
function expandParameters( action ) {
|
|
1678
|
+
// see also expandElements()
|
|
1679
|
+
if (!enableExpandElements || !effectiveType( action ))
|
|
1680
|
+
return;
|
|
1681
|
+
const chain = [];
|
|
1682
|
+
// Should we be able to consider params and returns separately?
|
|
1683
|
+
// Probably not, let to-csn omit unchanged params/returns.
|
|
1684
|
+
while (action._origin && !action.params) {
|
|
1685
|
+
chain.push( action );
|
|
1686
|
+
action = action._origin;
|
|
1687
|
+
}
|
|
1688
|
+
chain.reverse();
|
|
1689
|
+
for (const art of chain) {
|
|
1690
|
+
const origin = art._origin;
|
|
1691
|
+
if (!art.params && origin.params) {
|
|
1692
|
+
for (const name in origin.params) {
|
|
1693
|
+
// TODO: we could check _annotate here to decide whether we really
|
|
1694
|
+
// not to create proxies
|
|
1695
|
+
const orig = origin.params[name];
|
|
1696
|
+
linkToOrigin( orig, name, art, 'params', weakLocation( orig.location ), true )
|
|
1697
|
+
.$inferred = 'expand-param';
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
if (!art.returns && origin.returns) {
|
|
1701
|
+
// TODO: make linkToOrigin() work for returns, kind/name?
|
|
1702
|
+
const location = weakLocation( origin.returns.location );
|
|
1703
|
+
art.returns = {
|
|
1704
|
+
name: Object.assign( {}, art.name, { id: '', param: '', location } ),
|
|
1705
|
+
kind: 'param',
|
|
1706
|
+
location,
|
|
1707
|
+
$inferred: 'expand-param',
|
|
1708
|
+
};
|
|
1709
|
+
setProp( art.returns, '_parent', art );
|
|
1710
|
+
setProp( art.returns, '_main', art._main || art );
|
|
1711
|
+
setProp( art.returns, '_origin', origin.returns );
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1578
1715
|
|
|
1579
1716
|
function extensionFor( art ) {
|
|
1580
1717
|
if (art.kind === 'annotate')
|
|
@@ -1613,6 +1750,8 @@ function resolve( model ) {
|
|
|
1613
1750
|
ext.kind = 'annotate'; // after setMemberParent()!
|
|
1614
1751
|
setProp( art, '_extension', ext );
|
|
1615
1752
|
setProp( ext.name, '_artifact', art );
|
|
1753
|
+
if (art.returns)
|
|
1754
|
+
ext.$syntax = 'returns';
|
|
1616
1755
|
return ext;
|
|
1617
1756
|
}
|
|
1618
1757
|
|
|
@@ -1779,7 +1918,7 @@ function resolve( model ) {
|
|
|
1779
1918
|
function resolveQuery( query ) {
|
|
1780
1919
|
if (!query._main) // parse error
|
|
1781
1920
|
return;
|
|
1782
|
-
|
|
1921
|
+
traverseQueryPost( query, null, populateQuery );
|
|
1783
1922
|
forEachGeneric( query, '$tableAliases', ( alias ) => {
|
|
1784
1923
|
// console.log( info( null, [alias.location,alias], 'SQA:' ).toString() );
|
|
1785
1924
|
if (alias.kind === 'mixin')
|
|
@@ -1816,7 +1955,7 @@ function resolve( model ) {
|
|
|
1816
1955
|
return;
|
|
1817
1956
|
|
|
1818
1957
|
function resolveJoinOn( join ) {
|
|
1819
|
-
if (join.args) {
|
|
1958
|
+
if (join && join.args) { // JOIN
|
|
1820
1959
|
for (const j of join.args)
|
|
1821
1960
|
resolveJoinOn( j );
|
|
1822
1961
|
if (join.on)
|
|
@@ -1853,7 +1992,10 @@ function resolve( model ) {
|
|
|
1853
1992
|
}
|
|
1854
1993
|
const target = resolvePath( obj.target, 'target', art );
|
|
1855
1994
|
if (obj.on) {
|
|
1856
|
-
if (!art._main || !art._parent.elements && !art._parent.items) {
|
|
1995
|
+
if (!art._main || !art._parent.elements && !art._parent.items && !art._parent.targetAspect) {
|
|
1996
|
+
// TODO: test of .items a bit unclear - we should somehow restrict the
|
|
1997
|
+
// use of unmanaged assocs in MANY, at least with $self
|
|
1998
|
+
// TODO: $self usage in anonymous aspects to be corrected in Core Compiler
|
|
1857
1999
|
const isComposition = obj.type && obj.type.path && obj.type.path[0] &&
|
|
1858
2000
|
obj.type.path[0].id === 'cds.Composition';
|
|
1859
2001
|
message( 'assoc-as-type', [ obj.on.location, art ],
|
|
@@ -2294,6 +2436,9 @@ function resolve( model ) {
|
|
|
2294
2436
|
|
|
2295
2437
|
// TODO: there is no need to rewrite the on condition of non-leading queries,
|
|
2296
2438
|
// i.e. we could just have on = {…}
|
|
2439
|
+
// TODO: re-check $self rewrite (with managed composition of aspects),
|
|
2440
|
+
// and actually also $self inside anonymous aspect definitions
|
|
2441
|
+
// (not entirely urgent as we do not analyse it further, at least sole "$self")
|
|
2297
2442
|
function rewriteCondition( elem, assoc ) {
|
|
2298
2443
|
if (enableExpandElements && elem._parent && elem._parent.kind === 'element') {
|
|
2299
2444
|
// managed association as sub element not supported yet
|
|
@@ -2498,6 +2643,8 @@ function resolve( model ) {
|
|
|
2498
2643
|
}
|
|
2499
2644
|
|
|
2500
2645
|
function resolveExpr( expr, expected, user, extDict, expandOrInline) {
|
|
2646
|
+
// TODO: when we have rewritten the resolvePath functions,
|
|
2647
|
+
// define a traverseExpr() in ./utils.js
|
|
2501
2648
|
// TODO: extra "expected" 'expand'/'inline' instead o param `expandOrInline`
|
|
2502
2649
|
if (!expr || typeof expr === 'string') // parse error or keywords in {xpr:...}
|
|
2503
2650
|
return;
|
|
@@ -2534,7 +2681,7 @@ function resolve( model ) {
|
|
|
2534
2681
|
else if (expr.query) {
|
|
2535
2682
|
const { query } = expr;
|
|
2536
2683
|
if (query.kind || query._leadingQuery) { // UNION has _leadingQuery
|
|
2537
|
-
traverseQueryPost( query, false, resolveQuery );
|
|
2684
|
+
// traverseQueryPost( query, false, resolveQuery );
|
|
2538
2685
|
}
|
|
2539
2686
|
else {
|
|
2540
2687
|
error( 'expr-no-subquery', [ expr.location, user ], {},
|
|
@@ -2545,12 +2692,19 @@ function resolve( model ) {
|
|
|
2545
2692
|
const args = Array.isArray(expr.args) ? expr.args : Object.values( expr.args );
|
|
2546
2693
|
args.forEach( e => e && resolveExpr( e, e.$expected || expected, user, extDict ) );
|
|
2547
2694
|
}
|
|
2695
|
+
if (expr.suffix && isDeprecatedEnabled( options )) {
|
|
2696
|
+
const { location } = expr.suffix[0] || expr;
|
|
2697
|
+
error( null, [ location, user ], { prop: 'deprecated' },
|
|
2698
|
+
'Window functions are not supported if $(PROP) options are set' );
|
|
2699
|
+
}
|
|
2700
|
+
if (expr.suffix)
|
|
2701
|
+
expr.suffix.forEach( s => s && resolveExpr( s, expected, user, extDict ) );
|
|
2548
2702
|
}
|
|
2549
2703
|
|
|
2550
2704
|
function resolveParamsAndWhere( step, expected, user, extDict, isLast ) {
|
|
2551
2705
|
const alias = step._navigation && step._navigation.kind === '$tableAlias' && step._navigation;
|
|
2552
2706
|
const type = alias || effectiveType( step._artifact );
|
|
2553
|
-
const art = type && type.target
|
|
2707
|
+
const art = (type && type.target) ? type.target._artifact : type;
|
|
2554
2708
|
if (!art)
|
|
2555
2709
|
return;
|
|
2556
2710
|
const entity = (art.kind === 'entity') &&
|
|
@@ -2561,7 +2715,7 @@ function resolve( model ) {
|
|
|
2561
2715
|
if (step.where)
|
|
2562
2716
|
resolveExpr( step.where, 'filter', user, environment( type ) );
|
|
2563
2717
|
}
|
|
2564
|
-
else if (step.where || step.cardinality ) {
|
|
2718
|
+
else if (step.where && step.where.location || step.cardinality ) {
|
|
2565
2719
|
const location = combinedLocation( step.where, step.cardinality );
|
|
2566
2720
|
// XSN TODO: filter$location including […]
|
|
2567
2721
|
message( 'expr-no-filter', [ location, user ], { '#': expected },
|
|
@@ -2729,8 +2883,6 @@ function navProjection( navigation, preferred ) {
|
|
|
2729
2883
|
// Query tree post-order traversal - called for everything which makes a query
|
|
2730
2884
|
// except "real ones": operands of UNION etc, JOIN with ON, and sub queries in FROM
|
|
2731
2885
|
function traverseQueryPost( query, simpleOnly, callback ) {
|
|
2732
|
-
while (Array.isArray(query)) // query in parentheses, TODO: remove
|
|
2733
|
-
query = query[0];
|
|
2734
2886
|
if (!query) // parser error
|
|
2735
2887
|
return;
|
|
2736
2888
|
if (!query.op) { // in FROM (not JOIN)
|
|
@@ -2750,11 +2902,19 @@ function traverseQueryPost( query, simpleOnly, callback ) {
|
|
|
2750
2902
|
// console.log('FE:')
|
|
2751
2903
|
}
|
|
2752
2904
|
else if (query.args) { // JOIN, UNION, INTERSECT
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2905
|
+
if (!query.join && simpleOnly == null) {
|
|
2906
|
+
// enough for elements: traverse only first args for UNION/INTERSECT
|
|
2907
|
+
// TODO: we might use this also when we do not rewrite associations
|
|
2908
|
+
// in non-referred sub queries
|
|
2909
|
+
traverseQueryPost( query.args[0], simpleOnly, callback );
|
|
2910
|
+
}
|
|
2911
|
+
else {
|
|
2912
|
+
for (const q of query.args)
|
|
2913
|
+
traverseQueryPost( q, simpleOnly, callback );
|
|
2914
|
+
// The ON condition has to be traversed extra, because it must be evaluated
|
|
2915
|
+
// after the complete FROM has been traversed. It is also not necessary to
|
|
2916
|
+
// evaluate it in populateQuery().
|
|
2917
|
+
}
|
|
2758
2918
|
}
|
|
2759
2919
|
// else: with parse error (`select from <EOF>`, `select distinct from;`)
|
|
2760
2920
|
}
|