@sap/cds-compiler 2.15.6 → 2.15.10
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 +18 -0
- package/lib/compiler/populate.js +15 -0
- package/lib/edm/annotations/genericTranslation.js +25 -19
- package/lib/edm/annotations/preprocessAnnotations.js +6 -2
- package/lib/edm/edm.js +2 -2
- package/lib/json/from-csn.js +1 -0
- package/lib/json/to-csn.js +4 -2
- package/lib/render/toSql.js +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 2.15.10 - 2023-01-26
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- If an entity with parameters is auto-exposed, the generated projection now has
|
|
15
|
+
the same formal parameters and its query forwards these parameters to the origin entity.
|
|
16
|
+
- to.edm(x): Respect record type hint `$Type` in EDM JSON as full qualified `@type` URI property.
|
|
17
|
+
|
|
18
|
+
## Version 2.15.8 - 2022-08-02
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- to.edm(x): Nested `@UI.TextArrangement` has precedence over `@TextArrangement` shortcut annotation for `@Common.Text`.
|
|
23
|
+
- to.hdi.migration:
|
|
24
|
+
+ Respect option `disableHanaComments` when rendering the `ALTER` statements
|
|
25
|
+
+ Doc comments rendered the _full doc comment_ instead of only the first paragraph, as `to.hdi` does.
|
|
26
|
+
- compiler: An association's cardinality was lost for associations published in projections.
|
|
27
|
+
|
|
10
28
|
## Version 2.15.6 - 2022-07-26
|
|
11
29
|
|
|
12
30
|
### Fixed
|
package/lib/compiler/populate.js
CHANGED
|
@@ -1187,6 +1187,21 @@ function populate( model ) {
|
|
|
1187
1187
|
$inferred: '$generated',
|
|
1188
1188
|
},
|
|
1189
1189
|
};
|
|
1190
|
+
// forward target parameters to projection
|
|
1191
|
+
if (target.params) {
|
|
1192
|
+
art.params = Object.create(null);
|
|
1193
|
+
// is art.query.from.path[0].$syntax: ':' required?
|
|
1194
|
+
art.query.from.path[0].args = Object.create(null);
|
|
1195
|
+
forEachGeneric(target, 'params', (p, pn) => {
|
|
1196
|
+
art.params[pn] = linkToOrigin(p, pn, art, 'params', p.location);
|
|
1197
|
+
art.query.from.path[0].args[pn] = {
|
|
1198
|
+
name: { id: p.name.id, location: p.location },
|
|
1199
|
+
location: p.location,
|
|
1200
|
+
scope: 'param',
|
|
1201
|
+
path: [ { id: pn, location: p.location } ],
|
|
1202
|
+
};
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1190
1205
|
// TODO: do we need to tag the generated entity with elemScope = 'auto'?
|
|
1191
1206
|
if (autoexposed) {
|
|
1192
1207
|
Object.assign( autoexposed, art );
|
|
@@ -1144,28 +1144,30 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
|
|
|
1144
1144
|
// this type doesn't exist
|
|
1145
1145
|
message(warning, context, `explicitly specified type '${ actualTypeName }' not found in vocabulary`);
|
|
1146
1146
|
// explicitly mentioned type, render in XML and JSON
|
|
1147
|
-
newRecord.
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
// this type doesn't fit the expected one
|
|
1151
|
-
message(warning, context, `explicitly specified type '${ actualTypeName
|
|
1152
|
-
}' is not derived from expected type '${ dTypeName }'`);
|
|
1153
|
-
actualTypeName = dTypeName;
|
|
1154
|
-
// explicitly mentioned type, render in XML and JSON
|
|
1155
|
-
newRecord.setEdmAttribute('Type', actualTypeName);
|
|
1156
|
-
}
|
|
1157
|
-
else if (isAbstractType(actualTypeName)) {
|
|
1158
|
-
// this type is abstract
|
|
1159
|
-
message(warning, context, `explicitly specified type '${ actualTypeName }' is abstract, specify a concrete type`);
|
|
1160
|
-
if(dTypeName)
|
|
1161
|
-
actualTypeName = dTypeName;
|
|
1162
|
-
// set to definition name and render in XML and JSON
|
|
1163
|
-
newRecord.setEdmAttribute('Type', actualTypeName);
|
|
1147
|
+
newRecord.setXml({ 'Type': actualTypeName});
|
|
1148
|
+
// unknown dictionary type: can't fully qualify it
|
|
1149
|
+
newRecord.setJSON({ 'Type': actualTypeName});
|
|
1164
1150
|
}
|
|
1165
1151
|
else {
|
|
1166
|
-
|
|
1152
|
+
if (isAbstractType(actualTypeName)) {
|
|
1153
|
+
// this type is abstract
|
|
1154
|
+
message(warning, context, `explicitly specified type '${ actualTypeName }' is abstract, specify a concrete type`);
|
|
1155
|
+
if(dTypeName)
|
|
1156
|
+
actualTypeName = dTypeName;
|
|
1157
|
+
}
|
|
1158
|
+
else if (dTypeName && !isDerivedFrom(actualTypeName, dTypeName)) {
|
|
1159
|
+
// this type doesn't fit the expected one
|
|
1160
|
+
message(warning, context, `explicitly specified type '${ actualTypeName
|
|
1161
|
+
}' is not derived from expected type '${ dTypeName }'`);
|
|
1162
|
+
actualTypeName = dTypeName;
|
|
1163
|
+
}
|
|
1167
1164
|
// Dictionary Type, render in XML only for backward compatibility
|
|
1168
1165
|
newRecord.setXml( { Type: actualTypeName });
|
|
1166
|
+
const vocName = actualTypeName.slice(0, actualTypeName.indexOf('.'));
|
|
1167
|
+
const vocDef = vocabularyDefinitions[vocName];
|
|
1168
|
+
// Set full qualified type in JSON
|
|
1169
|
+
if(vocDef)
|
|
1170
|
+
newRecord.setJSON( { 'Type': `${vocDef.ref.Uri}#${actualTypeName}` });
|
|
1169
1171
|
}
|
|
1170
1172
|
}
|
|
1171
1173
|
else if (dTypeName) { // there is an expected type name according to dictionary
|
|
@@ -1323,7 +1325,11 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
|
|
|
1323
1325
|
const props = Object.create(null);
|
|
1324
1326
|
Object.entries(obj).forEach(([k, val]) => {
|
|
1325
1327
|
if(k === '@type') {
|
|
1326
|
-
edmNode.
|
|
1328
|
+
edmNode.setJSON({ 'Type': val});
|
|
1329
|
+
// try to shorten full qualified type URI to short type name
|
|
1330
|
+
const parts = val.split('#');
|
|
1331
|
+
const shortTypeName = parts[parts.length-1];
|
|
1332
|
+
edmNode.setXml({ Type: shortTypeName });
|
|
1327
1333
|
}
|
|
1328
1334
|
else {
|
|
1329
1335
|
let child = undefined;
|
|
@@ -297,8 +297,12 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
297
297
|
|
|
298
298
|
//change the scalar anno into a "pseudo-structured" one
|
|
299
299
|
// TODO should be flattened, but then alphabetical order is destroyed
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
|
|
301
|
+
// Do not overwrite existing nested annotation values, instead give existing
|
|
302
|
+
// nested annotation precedence and remove outer annotation (always)
|
|
303
|
+
if(!carrier['@Common.Text.@UI.TextArrangement'] && textAnno) {
|
|
304
|
+
carrier['@Common.Text'] = { '$value': textAnno, '@UI.TextArrangement': value };
|
|
305
|
+
}
|
|
302
306
|
delete carrier[aName];
|
|
303
307
|
}
|
|
304
308
|
}
|
package/lib/edm/edm.js
CHANGED
|
@@ -1351,8 +1351,8 @@ function getEdm(options, messageFunctions) {
|
|
|
1351
1351
|
{
|
|
1352
1352
|
toJSONattributes(json)
|
|
1353
1353
|
{
|
|
1354
|
-
if(this.
|
|
1355
|
-
json['@type'] = this.
|
|
1354
|
+
if(this._jsonOnlyAttributes.Type)
|
|
1355
|
+
json['@type'] = this._jsonOnlyAttributes.Type;
|
|
1356
1356
|
let keys = Object.keys(this._edmAttributes).filter(k => k !== 'Type');
|
|
1357
1357
|
for(const key of keys)
|
|
1358
1358
|
json['$'+key] = this._edmAttributes[key];
|
package/lib/json/from-csn.js
CHANGED
|
@@ -102,6 +102,7 @@ const ourpropsRegex = /^[_$]?[a-zA-Z]+[0-9]*$/;
|
|
|
102
102
|
const typeProperties = [
|
|
103
103
|
// do not include CSN v0.1.0 properties here:
|
|
104
104
|
'target', 'elements', 'enum', 'items',
|
|
105
|
+
'cardinality', // for association publishing in views
|
|
105
106
|
'type', 'length', 'precision', 'scale', 'srid', 'localized', 'notNull',
|
|
106
107
|
'keys', 'on', // only with 'target'
|
|
107
108
|
];
|
package/lib/json/to-csn.js
CHANGED
|
@@ -184,9 +184,11 @@ const propertyOrder = (function orderPositions() {
|
|
|
184
184
|
}());
|
|
185
185
|
|
|
186
186
|
// sync with definition in from-csn.js:
|
|
187
|
+
// Note: Order here is also the property order in CSN.
|
|
187
188
|
const typeProperties = [
|
|
188
|
-
'target', 'elements', 'enum', 'items',
|
|
189
|
-
'
|
|
189
|
+
'target', 'elements', 'enum', 'items',
|
|
190
|
+
'cardinality', // for association publishing in views
|
|
191
|
+
'type', 'length', 'precision', 'scale', 'srid', 'localized', // TODO: notNull?
|
|
190
192
|
'foreignKeys', 'on', // for explicit ON/keys with REDIRECTED
|
|
191
193
|
];
|
|
192
194
|
|
package/lib/render/toSql.js
CHANGED
|
@@ -200,7 +200,7 @@ function toSqlDdl(csn, options) {
|
|
|
200
200
|
Render comment string.
|
|
201
201
|
*/
|
|
202
202
|
comment(comment) {
|
|
203
|
-
return comment && renderStringForSql(comment, options.sqlDialect) || 'NULL';
|
|
203
|
+
return comment && renderStringForSql(getHanaComment({ doc: comment }), options.sqlDialect) || 'NULL';
|
|
204
204
|
},
|
|
205
205
|
/*
|
|
206
206
|
Alter SQL snippet for entity.
|
|
@@ -461,7 +461,7 @@ function toSqlDdl(csn, options) {
|
|
|
461
461
|
// Change entity properties
|
|
462
462
|
if (migration.properties) {
|
|
463
463
|
for (const [ prop, def ] of Object.entries(migration.properties)) {
|
|
464
|
-
if (prop === 'doc') {
|
|
464
|
+
if (prop === 'doc' && !options.disableHanaComments) { // def.new may be `null`
|
|
465
465
|
const alterComment = render.alterEntityComment(tableName, def.new);
|
|
466
466
|
addMigration(resultObj, artifactName, false, alterComment);
|
|
467
467
|
}
|
|
@@ -527,7 +527,7 @@ function toSqlDdl(csn, options) {
|
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
|
|
530
|
-
if (def.old.doc !== def.new.doc) {
|
|
530
|
+
if (!options.disableHanaComments && def.old.doc !== def.new.doc) {
|
|
531
531
|
const eltStrOldNoDoc = getEltStrNoProps(def.old, eltName, 'doc');
|
|
532
532
|
const eltStrNewNoDoc = getEltStrNoProps(def.new, eltName, 'doc');
|
|
533
533
|
if (eltStrOldNoDoc === eltStrNewNoDoc) { // only `doc` changed
|