@sap/cds-compiler 3.6.2 → 3.7.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 +49 -0
- package/README.md +3 -0
- package/bin/cdsc.js +9 -5
- package/doc/CHANGELOG_BETA.md +20 -2
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/lib/api/main.js +2 -1
- package/lib/base/dictionaries.js +10 -0
- package/lib/base/message-registry.js +56 -12
- package/lib/base/messages.js +39 -20
- package/lib/base/model.js +1 -0
- package/lib/base/shuffle.js +2 -1
- package/lib/checks/elements.js +29 -1
- package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +9 -5
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/onConditions.js +8 -5
- package/lib/checks/types.js +6 -1
- package/lib/checks/validator.js +7 -3
- package/lib/compiler/assert-consistency.js +20 -23
- package/lib/compiler/base.js +1 -2
- package/lib/compiler/builtins.js +2 -2
- package/lib/compiler/checks.js +237 -242
- package/lib/compiler/define.js +63 -75
- package/lib/compiler/extend.js +325 -22
- package/lib/compiler/finalize-parse-cdl.js +1 -55
- package/lib/compiler/kick-start.js +6 -7
- package/lib/compiler/populate.js +284 -288
- package/lib/compiler/propagator.js +15 -13
- package/lib/compiler/resolve.js +136 -306
- package/lib/compiler/shared.js +42 -44
- package/lib/compiler/tweak-assocs.js +29 -27
- package/lib/compiler/utils.js +29 -3
- package/lib/edm/annotations/genericTranslation.js +7 -13
- package/lib/edm/annotations/preprocessAnnotations.js +3 -0
- package/lib/edm/csn2edm.js +0 -4
- package/lib/edm/edm.js +6 -4
- package/lib/edm/edmAnnoPreprocessor.js +1 -0
- package/lib/edm/edmPreprocessor.js +1 -5
- package/lib/gen/Dictionary.json +34 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +2429 -2401
- package/lib/inspect/inspectPropagation.js +2 -0
- package/lib/json/from-csn.js +87 -41
- package/lib/json/to-csn.js +47 -16
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +109 -28
- package/lib/language/language.g4 +20 -4
- package/lib/model/csnRefs.js +1 -1
- package/lib/model/csnUtils.js +1 -0
- package/lib/model/revealInternalProperties.js +1 -2
- package/lib/modelCompare/compare.js +2 -1
- package/lib/render/manageConstraints.js +5 -2
- package/lib/render/toCdl.js +20 -7
- package/lib/render/toHdbcds.js +2 -8
- package/lib/render/toSql.js +4 -3
- package/lib/render/utils/common.js +9 -5
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/expansion.js +2 -0
- package/lib/transform/db/flattening.js +37 -36
- package/lib/transform/db/rewriteCalculatedElements.js +559 -0
- package/lib/transform/db/transformExists.js +4 -0
- package/lib/transform/db/views.js +40 -37
- package/lib/transform/forRelationalDB.js +38 -28
- package/lib/transform/odata/typesExposure.js +50 -15
- package/lib/transform/parseExpr.js +14 -8
- package/lib/transform/transformUtilsNew.js +6 -5
- package/lib/transform/translateAssocsToJoins.js +49 -33
- package/package.json +1 -1
package/lib/compiler/define.js
CHANGED
|
@@ -156,11 +156,10 @@ function define( model ) {
|
|
|
156
156
|
const { options } = model;
|
|
157
157
|
// Get simplified "resolve" functionality and the message function:
|
|
158
158
|
const {
|
|
159
|
-
error, warning, info, messages,
|
|
159
|
+
error, warning, info, message, messages,
|
|
160
160
|
} = model.$messageFunctions;
|
|
161
161
|
const {
|
|
162
162
|
resolveUncheckedPath,
|
|
163
|
-
checkAnnotate,
|
|
164
163
|
} = model.$functions;
|
|
165
164
|
const { shuffleDict, shuffleArray } = shuffleGen( options.testMode );
|
|
166
165
|
|
|
@@ -548,6 +547,7 @@ function define( model ) {
|
|
|
548
547
|
setLink( art, '_from', [] ); // for sequence of resolve steps
|
|
549
548
|
if (!setLink( art, '_leadingQuery', initQueryExpression( art.query, art ) ) )
|
|
550
549
|
return; // null or undefined in case of parse error
|
|
550
|
+
// if (art._leadingQuery !== art.$queries [0]) throw Error('FOO');
|
|
551
551
|
setLink( art._leadingQuery, '_$next', art );
|
|
552
552
|
if (art.elements) { // specified element via compilation of client-style CSN
|
|
553
553
|
// TODO: consider this part of a revamped on-demand 'extend' functionality
|
|
@@ -595,7 +595,7 @@ function define( model ) {
|
|
|
595
595
|
* - for members in compile(): init annotations via extendMembers/annotateMembers
|
|
596
596
|
* - for members in parse.cdl(): init annotation via initMembers
|
|
597
597
|
*
|
|
598
|
-
* In the future (after name cleanup):
|
|
598
|
+
* In the future (after name cleanup): -- TODO --
|
|
599
599
|
*
|
|
600
600
|
* - also initialize members and member extensions/annotations here
|
|
601
601
|
* - we might also do other things, like calculating whether an `extend` is
|
|
@@ -708,7 +708,6 @@ function define( model ) {
|
|
|
708
708
|
setLink( self, '_origin', query );
|
|
709
709
|
setLink( self, '_parent', query );
|
|
710
710
|
setLink( self, '_main', query._main );
|
|
711
|
-
setLink( self, '_effectiveType', query ); // TODO: remove
|
|
712
711
|
query.$tableAliases.$self = self;
|
|
713
712
|
query.$tableAliases.$projection = self;
|
|
714
713
|
}
|
|
@@ -770,6 +769,7 @@ function define( model ) {
|
|
|
770
769
|
// _origin is set when we resolve the ref
|
|
771
770
|
if (query._parent.kind !== 'select')
|
|
772
771
|
query._main._from.push( table ); // store tabref if outside "real" subquery
|
|
772
|
+
// (tab refs on the right of union are unnecessary)
|
|
773
773
|
}
|
|
774
774
|
else if (table.query) {
|
|
775
775
|
if (!table.name || !table.name.id) {
|
|
@@ -778,7 +778,6 @@ function define( model ) {
|
|
|
778
778
|
return;
|
|
779
779
|
}
|
|
780
780
|
addAsAlias();
|
|
781
|
-
setLink( table, '_effectiveType', table.query ); // TODO: remove!
|
|
782
781
|
// Store _origin to leading query of table.query for name resolution
|
|
783
782
|
setLink( table, '_origin', initQueryExpression( table.query, table ) );
|
|
784
783
|
}
|
|
@@ -1010,12 +1009,14 @@ function define( model ) {
|
|
|
1010
1009
|
*
|
|
1011
1010
|
* If not for extensions: construct === parent
|
|
1012
1011
|
*
|
|
1012
|
+
* Param `initExtensions` is for parse.cdl
|
|
1013
|
+
*
|
|
1013
1014
|
* TODO: separate extension!
|
|
1014
1015
|
*/
|
|
1015
1016
|
function initMembers( construct, parent, block, initExtensions = false ) {
|
|
1016
1017
|
// TODO: split extend from init
|
|
1017
1018
|
const main = parent._main || parent;
|
|
1018
|
-
const isQueryExtension =
|
|
1019
|
+
const isQueryExtension = construct.kind === 'extend' && main.query;
|
|
1019
1020
|
let obj = construct;
|
|
1020
1021
|
let { items } = obj;
|
|
1021
1022
|
while (items) {
|
|
@@ -1043,46 +1044,8 @@ function define( model ) {
|
|
|
1043
1044
|
'A managed aspect composition can\'t have a specified ON-condition' );
|
|
1044
1045
|
delete obj.on; // continuation semantics: not specified
|
|
1045
1046
|
}
|
|
1046
|
-
if (targetAspect.elements)
|
|
1047
|
-
|
|
1048
|
-
const inEntity = parent._main && parent._main.kind === 'entity';
|
|
1049
|
-
// TODO: also allow indirectly (component in component in entity)?
|
|
1050
|
-
setLink( targetAspect, '_outer', obj );
|
|
1051
|
-
setLink( targetAspect, '_parent', parent._parent );
|
|
1052
|
-
setLink( targetAspect, '_main', null ); // for name resolution
|
|
1053
|
-
|
|
1054
|
-
parent = targetAspect;
|
|
1055
|
-
construct = parent; // avoid extension behavior
|
|
1056
|
-
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1057
|
-
setLink( targetAspect, '_block', block );
|
|
1058
|
-
initDollarSelf( targetAspect );
|
|
1059
|
-
// allow ref of up_ in anonymous aspect inside entity
|
|
1060
|
-
// (TODO: complain if used and the managed composition is included into
|
|
1061
|
-
// another entity - might induce auto-redirection):
|
|
1062
|
-
if (inEntity && !targetAspect.elements.up_) {
|
|
1063
|
-
const up = {
|
|
1064
|
-
name: {
|
|
1065
|
-
id: 'up_',
|
|
1066
|
-
alias: 'up_',
|
|
1067
|
-
element: obj.name.element,
|
|
1068
|
-
absolute: obj.name.absolute,
|
|
1069
|
-
},
|
|
1070
|
-
kind: '$navElement',
|
|
1071
|
-
location: obj.location,
|
|
1072
|
-
};
|
|
1073
|
-
setLink( up, '_parent', targetAspect );
|
|
1074
|
-
setLink( up, '_main', targetAspect ); // used on main artifact
|
|
1075
|
-
// recompilation case: both target and targetAspect → allow up_ in that case, too:
|
|
1076
|
-
const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
|
|
1077
|
-
const entity = name && model.definitions[name];
|
|
1078
|
-
if (entity && entity.elements)
|
|
1079
|
-
setLink( up, '_origin', entity.elements.up_ );
|
|
1080
|
-
// processAspectComposition/expand() sets _origin to element of
|
|
1081
|
-
// generated target entity
|
|
1082
|
-
targetAspect.$tableAliases.up_ = up;
|
|
1083
|
-
}
|
|
1084
|
-
obj = targetAspect;
|
|
1085
|
-
}
|
|
1047
|
+
if (targetAspect.elements)
|
|
1048
|
+
initAnonymousAspect();
|
|
1086
1049
|
}
|
|
1087
1050
|
if (obj !== parent && obj.elements && parent.enum) { // applying the extension
|
|
1088
1051
|
initElementsAsEnum();
|
|
@@ -1102,7 +1065,8 @@ function define( model ) {
|
|
|
1102
1065
|
forEachInOrder( construct, 'params', init );
|
|
1103
1066
|
const { returns } = construct;
|
|
1104
1067
|
if (returns) {
|
|
1105
|
-
|
|
1068
|
+
const { kind } = construct;
|
|
1069
|
+
returns.kind = (kind === 'extend' || kind === 'annotate') ? kind : 'param';
|
|
1106
1070
|
init( returns, '' ); // '' is special name for returns parameter
|
|
1107
1071
|
}
|
|
1108
1072
|
return;
|
|
@@ -1129,6 +1093,47 @@ function define( model ) {
|
|
|
1129
1093
|
forEachGeneric( { enum: obj.elements }, 'enum', init );
|
|
1130
1094
|
}
|
|
1131
1095
|
|
|
1096
|
+
function initAnonymousAspect() {
|
|
1097
|
+
// TODO: main?
|
|
1098
|
+
const inEntity = parent._main && parent._main.kind === 'entity';
|
|
1099
|
+
// TODO: also allow indirectly (component in component in entity)?
|
|
1100
|
+
setLink( targetAspect, '_outer', obj );
|
|
1101
|
+
setLink( targetAspect, '_parent', parent._parent );
|
|
1102
|
+
setLink( targetAspect, '_main', null ); // for name resolution
|
|
1103
|
+
|
|
1104
|
+
parent = targetAspect;
|
|
1105
|
+
construct = parent; // avoid extension behavior
|
|
1106
|
+
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1107
|
+
setLink( targetAspect, '_block', block );
|
|
1108
|
+
initDollarSelf( targetAspect );
|
|
1109
|
+
// allow ref of up_ in anonymous aspect inside entity
|
|
1110
|
+
// (TODO: complain if used and the managed composition is included into
|
|
1111
|
+
// another entity - might induce auto-redirection):
|
|
1112
|
+
if (inEntity && !targetAspect.elements.up_) {
|
|
1113
|
+
const up = {
|
|
1114
|
+
name: {
|
|
1115
|
+
id: 'up_',
|
|
1116
|
+
alias: 'up_',
|
|
1117
|
+
element: obj.name.element,
|
|
1118
|
+
absolute: obj.name.absolute,
|
|
1119
|
+
},
|
|
1120
|
+
kind: '$navElement',
|
|
1121
|
+
location: obj.location,
|
|
1122
|
+
};
|
|
1123
|
+
setLink( up, '_parent', targetAspect );
|
|
1124
|
+
setLink( up, '_main', targetAspect ); // used on main artifact
|
|
1125
|
+
// recompilation case: both target and targetAspect → allow up_ in that case, too:
|
|
1126
|
+
const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
|
|
1127
|
+
const entity = name && model.definitions[name];
|
|
1128
|
+
if (entity && entity.elements)
|
|
1129
|
+
setLink( up, '_origin', entity.elements.up_ );
|
|
1130
|
+
// processAspectComposition/expand() sets _origin to element of
|
|
1131
|
+
// generated target entity
|
|
1132
|
+
targetAspect.$tableAliases.up_ = up;
|
|
1133
|
+
}
|
|
1134
|
+
obj = targetAspect;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1132
1137
|
function init( elem, name, prop ) {
|
|
1133
1138
|
if (!elem.kind) // wrong CSN input
|
|
1134
1139
|
elem.kind = dictKinds[prop];
|
|
@@ -1138,12 +1143,12 @@ function define( model ) {
|
|
|
1138
1143
|
elem.name = Object.assign( { $inferred: 'as' },
|
|
1139
1144
|
ref.path[ref.path.length - 1] );
|
|
1140
1145
|
}
|
|
1141
|
-
else { //
|
|
1146
|
+
else { // RETURNS, parser robustness
|
|
1142
1147
|
elem.name = { id: name, location: elem.location };
|
|
1143
1148
|
}
|
|
1144
1149
|
}
|
|
1145
1150
|
// if (!kindProperties[ elem.kind ]) console.log(elem.kind,elem.name)
|
|
1146
|
-
if (
|
|
1151
|
+
if ((elem.kind === 'extend' || elem.kind === 'annotate') && !initExtensions) {
|
|
1147
1152
|
storeExtension( elem, name, prop, parent, block );
|
|
1148
1153
|
return;
|
|
1149
1154
|
}
|
|
@@ -1161,8 +1166,6 @@ function define( model ) {
|
|
|
1161
1166
|
setMemberParent( elem, name, parent, add && prop );
|
|
1162
1167
|
// console.log(message( null, elem.location, elem, {}, 'Info', 'INIT').toString())
|
|
1163
1168
|
checkRedefinition( elem );
|
|
1164
|
-
if (elem.kind === 'annotate' || elem.kind === 'extend')
|
|
1165
|
-
checkAnnotate( elem, elem );
|
|
1166
1169
|
initAnnotations( elem, bl );
|
|
1167
1170
|
initMembers( elem, elem, bl, initExtensions );
|
|
1168
1171
|
if (boundSelfParamType && (elem.kind === 'action' || elem.kind === 'function'))
|
|
@@ -1174,31 +1177,16 @@ function define( model ) {
|
|
|
1174
1177
|
elem.$syntax === 'enum' && parent.kind === 'extend') // ambiguous in parse-cdl
|
|
1175
1178
|
return;
|
|
1176
1179
|
// -> it's a calculated element
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
function checkCalculatedElement( elem ) {
|
|
1183
|
-
const loc = [ elem.value.location, elem ];
|
|
1184
|
-
if (elem._main.kind !== 'entity' && elem._main.kind !== 'aspect' &&
|
|
1185
|
-
elem._main.kind !== 'extend') {
|
|
1186
|
-
error( 'syntax-invalid-calc-elem', loc, { '#': elem._main.kind } );
|
|
1187
|
-
}
|
|
1188
|
-
else if (!isBetaEnabled( options, 'calculatedElements' )) {
|
|
1189
|
-
error( 'def-unsupported-calc-elem', loc,
|
|
1190
|
-
'Calculated elements are not supported' );
|
|
1191
|
-
}
|
|
1192
|
-
else {
|
|
1193
|
-
const noTruthyAllowed = [ 'localized', 'key', 'virtual' ];
|
|
1194
|
-
for (const prop of noTruthyAllowed) {
|
|
1195
|
-
if (elem[prop]?.val) {
|
|
1196
|
-
// probably better than a parse error (which is good for DEFAULT vs calc),
|
|
1197
|
-
// also appears with parse-cdl:
|
|
1198
|
-
error('syntax-invalid-calc-elem', loc, { '#': prop });
|
|
1199
|
-
return; // one error is enough
|
|
1200
|
-
}
|
|
1180
|
+
if (!elem.type && elem.value?.type) { // top-level CAST( expr AS type )
|
|
1181
|
+
if (!elem.target)
|
|
1182
|
+
elem.type = { ...elem.value.type, $inferred: 'cast' };
|
|
1201
1183
|
}
|
|
1184
|
+
if (!isBetaEnabled( options, 'calculatedElements' )) {
|
|
1185
|
+
const loc = [ elem.value.location, elem ];
|
|
1186
|
+
// TODO: this could be considered a syntax check
|
|
1187
|
+
message( 'def-unsupported-calc-elem', loc, { '#': 'std' } );
|
|
1188
|
+
}
|
|
1189
|
+
elem.$syntax = 'calc';
|
|
1202
1190
|
}
|
|
1203
1191
|
}
|
|
1204
1192
|
|