@sap/cds-compiler 2.12.0 → 2.15.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 +221 -15
- package/bin/cdsc.js +125 -50
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +47 -84
- package/lib/api/options.js +5 -6
- package/lib/api/validate.js +6 -11
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +114 -18
- package/lib/base/messages.js +101 -90
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +177 -123
- package/lib/checks/annotationsOData.js +12 -33
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +6 -11
- package/lib/compiler/assert-consistency.js +6 -3
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +19 -6
- package/lib/compiler/checks.js +23 -60
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1151 -0
- package/lib/compiler/extend.js +1000 -0
- package/lib/compiler/finalize-parse-cdl.js +237 -0
- package/lib/compiler/index.js +107 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1227 -0
- package/lib/compiler/propagator.js +114 -46
- package/lib/compiler/resolve.js +1521 -0
- package/lib/compiler/shared.js +126 -65
- package/lib/compiler/tweak-assocs.js +535 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -24
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +219 -100
- package/lib/edm/edm.js +302 -230
- package/lib/edm/edmPreprocessor.js +554 -419
- package/lib/edm/edmUtils.js +138 -44
- package/lib/gen/Dictionary.json +100 -19
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5765 -4480
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +15 -3
- package/lib/json/to-csn.js +126 -68
- package/lib/language/docCommentParser.js +4 -4
- package/lib/language/genericAntlrParser.js +123 -5
- package/lib/language/language.g4 +355 -156
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +486 -59
- package/lib/main.js +41 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +252 -156
- package/lib/model/csnUtils.js +384 -297
- package/lib/model/enrichCsn.js +71 -29
- package/lib/model/revealInternalProperties.js +29 -8
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +23 -18
- package/lib/optionProcessor.js +63 -26
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +897 -947
- package/lib/render/toHdbcds.js +205 -257
- package/lib/render/toSql.js +264 -225
- package/lib/render/utils/common.js +136 -25
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +3 -1
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +104 -306
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +58 -53
- package/lib/transform/db/expansion.js +60 -33
- package/lib/transform/db/flattening.js +582 -104
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +66 -13
- package/lib/transform/db/views.js +11 -7
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +109 -208
- package/lib/transform/forOdataNew.js +59 -212
- package/lib/transform/localized.js +46 -26
- package/lib/transform/odata/toFinalBaseType.js +85 -11
- package/lib/transform/odata/typesExposure.js +147 -199
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +44 -33
- package/lib/transform/translateAssocsToJoins.js +3 -20
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +172 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/moduleResolve.js +13 -6
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -290
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
- package/lib/transform/universalCsnEnricher.js +0 -237
package/lib/model/enrichCsn.js
CHANGED
|
@@ -61,10 +61,14 @@ function enrichCsn( csn, options = {} ) {
|
|
|
61
61
|
// TODO: excluding
|
|
62
62
|
'@': () => { /* ignore annotations */ },
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
const { inspectRef, artifactRef, getOrigin, __getCache_forEnrichCsnDebugging } =
|
|
66
|
-
csnRefs( csn );
|
|
64
|
+
// options.enrichCsn = 'DEBUG';
|
|
67
65
|
let $$cacheObjectNumber = 0; // for debugging
|
|
66
|
+
const debugLocationInfo = options.enrichCsn === 'DEBUG' && Object.create(null);
|
|
67
|
+
|
|
68
|
+
setLocations( csn, false, null );
|
|
69
|
+
const { inspectRef, artifactRef, getOrigin, initDefinition, __getCache_forEnrichCsnDebugging } =
|
|
70
|
+
csnRefs( csn, true );
|
|
71
|
+
|
|
68
72
|
const csnPath = [];
|
|
69
73
|
if (csn.definitions)
|
|
70
74
|
dictionary( csn, 'definitions', csn.definitions );
|
|
@@ -107,6 +111,8 @@ function enrichCsn( csn, options = {} ) {
|
|
|
107
111
|
return;
|
|
108
112
|
csnPath.push( prop );
|
|
109
113
|
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
114
|
+
if (prop === 'definitions')
|
|
115
|
+
initDefinition( dict[name] );
|
|
110
116
|
definition( dict, name, dict[name] );
|
|
111
117
|
}
|
|
112
118
|
if (!Object.prototype.propertyIsEnumerable.call( parent, prop ))
|
|
@@ -115,11 +121,19 @@ function enrichCsn( csn, options = {} ) {
|
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
function refLocation( art ) {
|
|
118
|
-
if (art
|
|
119
|
-
|
|
124
|
+
if (!art || typeof art !== 'object' || Array.isArray( art )) {
|
|
125
|
+
if (!options.testMode)
|
|
126
|
+
return (typeof art === 'string')
|
|
127
|
+
? `<illegal ref = ${art}>`
|
|
128
|
+
: `<illegal ref: ${typeof art}>`;
|
|
129
|
+
throw new Error( 'Illegal reference' );
|
|
130
|
+
}
|
|
131
|
+
else if (art.$location)
|
|
132
|
+
return art.$location;
|
|
133
|
+
|
|
120
134
|
if (!options.testMode)
|
|
121
|
-
return art
|
|
122
|
-
throw new Error( '
|
|
135
|
+
return `<${Object.keys( art ).join('+')}+!$location>`;
|
|
136
|
+
throw new Error( 'Reference to object without $location' );
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
function simpleRef( parent, prop, ref ) {
|
|
@@ -138,6 +152,7 @@ function enrichCsn( csn, options = {} ) {
|
|
|
138
152
|
else { // targetAspect, target
|
|
139
153
|
csnPath.push( prop );
|
|
140
154
|
dictionary( ref, 'elements', ref.elements );
|
|
155
|
+
_cache_debug( ref );
|
|
141
156
|
csnPath.pop();
|
|
142
157
|
}
|
|
143
158
|
// } catch (e) {
|
|
@@ -242,6 +257,10 @@ function enrichCsn( csn, options = {} ) {
|
|
|
242
257
|
obj.$$cacheObject[name] = sub;
|
|
243
258
|
}
|
|
244
259
|
}
|
|
260
|
+
else if (name === '$origin$step') { // string value handled above
|
|
261
|
+
const kind = Object.keys( val )[0];
|
|
262
|
+
obj.$$cacheObject[name] = `${kind}: ${ val[kind] }`;
|
|
263
|
+
}
|
|
245
264
|
else if (Array.isArray( val )) {
|
|
246
265
|
obj.$$cacheObject[name] = val.map( item => {
|
|
247
266
|
if (!item.$$objectNumber)
|
|
@@ -257,8 +276,53 @@ function enrichCsn( csn, options = {} ) {
|
|
|
257
276
|
}
|
|
258
277
|
}
|
|
259
278
|
}
|
|
279
|
+
|
|
280
|
+
function debugLocation( loc, userProvided ) {
|
|
281
|
+
if (debugLocationInfo && !userProvided) {
|
|
282
|
+
loc = loc.replace( /\([0-9]+\)\^/, '^' );
|
|
283
|
+
debugLocationInfo[loc] = (debugLocationInfo[loc] || 0) + 1;
|
|
284
|
+
loc = `${loc}(${debugLocationInfo[loc]})`;
|
|
285
|
+
}
|
|
286
|
+
return loc;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function setLocations( node, prop, loc ) {
|
|
290
|
+
if (!node || typeof node !== 'object')
|
|
291
|
+
return;
|
|
292
|
+
const isMember = artifactProperties.includes( prop );
|
|
293
|
+
if (!isMember && node.$location) {
|
|
294
|
+
if (typeof node.$location === 'string') // already set for nested 'items'
|
|
295
|
+
return;
|
|
296
|
+
loc = locationString( node.$location, true );
|
|
297
|
+
if (!node.SELECT) // compatibility: $location of query both inside and as sibling of SELECT
|
|
298
|
+
reveal( node, '$location', debugLocation( loc, !node.$generated ) );
|
|
299
|
+
}
|
|
300
|
+
else if (prop === true || prop === 'returns') { // in dictionary or returns
|
|
301
|
+
loc = debugLocation( loc + '^' );
|
|
302
|
+
node.$location = loc;
|
|
303
|
+
}
|
|
304
|
+
else if (prop === 'items') {
|
|
305
|
+
let iloc = loc + '[]';
|
|
306
|
+
let obj = node;
|
|
307
|
+
while (obj) {
|
|
308
|
+
// should not appear in --enrich-csn, only for _origin info
|
|
309
|
+
Object.defineProperty( obj, '$location', { value: iloc, enumerable: false } );
|
|
310
|
+
obj = obj.items;
|
|
311
|
+
iloc += '[]';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (Array.isArray( node )) {
|
|
315
|
+
for (const item of node)
|
|
316
|
+
setLocations( item, isMember, loc );
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
for (const name of Object.getOwnPropertyNames( node ))
|
|
320
|
+
setLocations( node[name], isMember || name, loc );
|
|
321
|
+
}
|
|
322
|
+
}
|
|
260
323
|
}
|
|
261
324
|
|
|
325
|
+
|
|
262
326
|
function reveal( node, prop, value ) {
|
|
263
327
|
Object.defineProperty( node, prop, {
|
|
264
328
|
value,
|
|
@@ -268,26 +332,4 @@ function reveal( node, prop, value ) {
|
|
|
268
332
|
} );
|
|
269
333
|
}
|
|
270
334
|
|
|
271
|
-
function setLocations( node, prop, loc ) {
|
|
272
|
-
if (!node || typeof node !== 'object')
|
|
273
|
-
return;
|
|
274
|
-
const isMember = artifactProperties.includes( prop );
|
|
275
|
-
if (!isMember && node.$location) {
|
|
276
|
-
loc = locationString( node.$location, true );
|
|
277
|
-
reveal( node, '$location', loc );
|
|
278
|
-
}
|
|
279
|
-
else if (prop === true) {
|
|
280
|
-
loc += '^';
|
|
281
|
-
node.$location = loc;
|
|
282
|
-
}
|
|
283
|
-
if (Array.isArray( node )) {
|
|
284
|
-
for (const item of node)
|
|
285
|
-
setLocations( item, isMember, loc );
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
for (const name of Object.getOwnPropertyNames( node ))
|
|
289
|
-
setLocations( node[name], isMember || name, loc );
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
335
|
module.exports = enrichCsn;
|
|
@@ -36,7 +36,7 @@ const kindsRepresentedAsLinks = {
|
|
|
36
36
|
// represent table alias in from / join-args property as link:
|
|
37
37
|
$tableAlias: tableAliasAsLink,
|
|
38
38
|
// represent "navigation elemens" in _combined as links:
|
|
39
|
-
$navElement: (art, parent) => art._parent && parent !== art._parent.elements,
|
|
39
|
+
$navElement: (art, parent) => art._parent && parent !== art._parent.elements && art._parent.kind !== 'aspect',
|
|
40
40
|
// represent mixin in $tableAliases as link:
|
|
41
41
|
mixin: tableAliasAsLink,
|
|
42
42
|
// represent $projection as link, as it is just another search name for $self:
|
|
@@ -50,7 +50,16 @@ function tableAliasAsLink( art, parent, name ) {
|
|
|
50
50
|
parent === art._parent.$tableAliases[name].$duplicates);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Reveal internal properties of `model` for the given artifact name (or path).
|
|
55
|
+
* `path` could be a definition name or a `/`-separated XSN path such as
|
|
56
|
+
* `name.space/S/E/elements/a/type/scope/`.
|
|
57
|
+
*
|
|
58
|
+
* @param {XSN.Model} model
|
|
59
|
+
* @param {string} [nameOrPath]
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
function revealInternalProperties( model, nameOrPath ) {
|
|
54
63
|
const transformers = {
|
|
55
64
|
messages: m => m,
|
|
56
65
|
name: shortenName,
|
|
@@ -76,6 +85,7 @@ function revealInternalProperties( model, name ) {
|
|
|
76
85
|
$tableAliases: dictionary,
|
|
77
86
|
$duplicates: duplicates,
|
|
78
87
|
$keysNavigation: dictionary,
|
|
88
|
+
targetAspect,
|
|
79
89
|
$layerNumber: n => n,
|
|
80
90
|
$extra: e => e,
|
|
81
91
|
_layerRepresentative: s => s.realname,
|
|
@@ -89,7 +99,7 @@ function revealInternalProperties( model, name ) {
|
|
|
89
99
|
$messageFunctions: () => '‹some functions›',
|
|
90
100
|
}
|
|
91
101
|
unique_id = 1;
|
|
92
|
-
return revealXsnPath(
|
|
102
|
+
return revealXsnPath(nameOrPath, model);
|
|
93
103
|
|
|
94
104
|
// Returns the desired artifact/dictionary in the XSN.
|
|
95
105
|
//
|
|
@@ -119,7 +129,7 @@ function revealInternalProperties( model, name ) {
|
|
|
119
129
|
|
|
120
130
|
path = path.split('/');
|
|
121
131
|
if (path.length === 1) {
|
|
122
|
-
return reveal( xsn.definitions[path] );
|
|
132
|
+
return reveal( xsn.definitions[path] || xsn.vocabularies && xsn.vocabularies[path] );
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
// with the code below, we might miss the right transformer function
|
|
@@ -259,6 +269,12 @@ function revealInternalProperties( model, name ) {
|
|
|
259
269
|
return r;
|
|
260
270
|
}
|
|
261
271
|
|
|
272
|
+
function targetAspect( node, parent ) {
|
|
273
|
+
if (node.elements && unique_id && node.__unique_id__ == null)
|
|
274
|
+
Object.defineProperty( node, '__unique_id__', { value: ++unique_id } );
|
|
275
|
+
return reveal( node, parent );
|
|
276
|
+
}
|
|
277
|
+
|
|
262
278
|
function duplicates( node, parent ) {
|
|
263
279
|
return reveal( node, parent, parent.name && parent.name.id );
|
|
264
280
|
}
|
|
@@ -272,10 +288,12 @@ function artifactIdentifier( node, parent ) {
|
|
|
272
288
|
let outer = unique_id ? '##' + node.__unique_id__ : '';
|
|
273
289
|
if (node._outer) {
|
|
274
290
|
if (node.$inferred === 'REDIRECTED')
|
|
275
|
-
outer = '/redirected';
|
|
291
|
+
outer = '/redirected' + outer;
|
|
276
292
|
else
|
|
277
|
-
outer = (node._outer.items === node) ? '/items'
|
|
278
|
-
: (node._outer.returns === node) ? '/returns'
|
|
293
|
+
outer = (node._outer.items === node) ? '/items' + outer
|
|
294
|
+
: (node._outer.returns === node) ? '/returns' + outer
|
|
295
|
+
: (node._outer.targetAspect === node) ? '/target' + outer
|
|
296
|
+
: '/returns/items' + outer;
|
|
279
297
|
node = node._outer;
|
|
280
298
|
}
|
|
281
299
|
if (node === parent)
|
|
@@ -305,7 +323,10 @@ function artifactIdentifier( node, parent ) {
|
|
|
305
323
|
return 'source:' + quoted( node.location && node.location.file ) +
|
|
306
324
|
'/using:' + quoted( node.name.id )
|
|
307
325
|
default: {
|
|
308
|
-
|
|
326
|
+
let main = node._main;
|
|
327
|
+
while (main && main._outer) // anonymous aspect
|
|
328
|
+
main = main._outer._main;
|
|
329
|
+
return ((main || node).kind || '<kind>') + ':' + msg.artName( node ) + outer;
|
|
309
330
|
}
|
|
310
331
|
}
|
|
311
332
|
}
|
package/lib/model/sortViews.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const {setDependencies} = require('./csnUtils');
|
|
3
|
+
const { ModelError } = require("../base/error");
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {Object} Layers
|
|
@@ -91,7 +92,7 @@ module.exports = function({sql, csn}){
|
|
|
91
92
|
const { layers, leftover } = sortTopologically(csn, _dependents, _dependencies);
|
|
92
93
|
cleanup.forEach(fn => fn());
|
|
93
94
|
if(leftover.length > 0)
|
|
94
|
-
throw new
|
|
95
|
+
throw new ModelError('Unable to build a correct dependency graph! Are there cycles?');
|
|
95
96
|
|
|
96
97
|
const result = [];
|
|
97
98
|
// keep the "artifact name" - needed for to.hdi sorting
|
|
@@ -6,13 +6,14 @@ const {
|
|
|
6
6
|
forEachMember,
|
|
7
7
|
hasAnnotationValue
|
|
8
8
|
} = require('../model/csnUtils');
|
|
9
|
+
const { isBetaEnabled } = require('../base/model');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Compares two models, in HANA-transformed CSN format, to each other.
|
|
12
13
|
*
|
|
13
14
|
* @param beforeModel the before-model
|
|
14
15
|
* @param afterModel the after-model
|
|
15
|
-
* @param {
|
|
16
|
+
* @param {HdiOptions|false} options
|
|
16
17
|
* @returns {object} the sets of deletions, extensions, and migrations of entities necessary to transform the before-model
|
|
17
18
|
* to the after-model, together with all the definitions of the after-model
|
|
18
19
|
*/
|
|
@@ -26,8 +27,8 @@ function compareModels(beforeModel, afterModel, options) {
|
|
|
26
27
|
const migrations = []; // element changes/removals or changes of entity properties
|
|
27
28
|
|
|
28
29
|
// There is currently no use in knowing the added entities only. If this changes, hand in `addedEntities` to `getArtifactComparator` below.
|
|
29
|
-
forEachDefinition(afterModel, getArtifactComparator(beforeModel, null, null, elementAdditions, migrations));
|
|
30
|
-
forEachDefinition(beforeModel, getArtifactComparator(afterModel, null, deletedEntities, null, null));
|
|
30
|
+
forEachDefinition(afterModel, getArtifactComparator(beforeModel, options, null, null, elementAdditions, migrations));
|
|
31
|
+
forEachDefinition(beforeModel, getArtifactComparator(afterModel, options, null, deletedEntities, null, null));
|
|
31
32
|
|
|
32
33
|
const returnObj = Object.create(null);
|
|
33
34
|
returnObj.definitions = afterModel.definitions;
|
|
@@ -44,23 +45,23 @@ function validateCsnVersions(beforeModel, afterModel, options) {
|
|
|
44
45
|
let afterVersionParts = afterVersion && afterVersion.split('.');
|
|
45
46
|
|
|
46
47
|
if (!beforeVersionParts || beforeVersionParts.length < 2) {
|
|
47
|
-
const { error,
|
|
48
|
+
const { error, throwWithAnyError } = makeMessageFunction(beforeModel, options, 'modelCompare');
|
|
48
49
|
error(null, null, `Invalid CSN version: ${beforeVersion}`);
|
|
49
|
-
|
|
50
|
+
throwWithAnyError();
|
|
50
51
|
}
|
|
51
52
|
if (!afterVersionParts || afterVersionParts.length < 2) {
|
|
52
|
-
const { error,
|
|
53
|
+
const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
|
|
53
54
|
error(null, null, `Invalid CSN version: ${afterVersion}`);
|
|
54
|
-
|
|
55
|
+
throwWithAnyError();
|
|
55
56
|
}
|
|
56
57
|
if (beforeVersionParts[0] > afterVersionParts[0] && !(options && options.allowCsnDowngrade)) {
|
|
57
|
-
const { error,
|
|
58
|
+
const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
|
|
58
59
|
error(null, null, `Incompatible CSN versions: ${afterVersion} is a major downgrade from ${beforeVersion}. Is @sap/cds-compiler version ${require('../../package.json').version} outdated?`);
|
|
59
|
-
|
|
60
|
+
throwWithAnyError();
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
function getArtifactComparator(otherModel, addedEntities, deletedEntities, elementAdditions, migrations) {
|
|
64
|
+
function getArtifactComparator(otherModel, options, addedEntities, deletedEntities, elementAdditions, migrations) {
|
|
64
65
|
return function compareArtifacts(artifact, name) {
|
|
65
66
|
function addElements() {
|
|
66
67
|
const elements = {};
|
|
@@ -70,7 +71,11 @@ function getArtifactComparator(otherModel, addedEntities, deletedEntities, eleme
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
function changePropsOrRemoveOrChangeElements() {
|
|
73
|
-
const relevantProperties = [
|
|
74
|
+
const relevantProperties = [
|
|
75
|
+
{ name: 'doc' },
|
|
76
|
+
{ name: '@sql.prepend' },
|
|
77
|
+
{ name: '@sql.append' },
|
|
78
|
+
];
|
|
74
79
|
const changedProperties = {};
|
|
75
80
|
|
|
76
81
|
const removedElements = {};
|
|
@@ -79,8 +84,8 @@ function getArtifactComparator(otherModel, addedEntities, deletedEntities, eleme
|
|
|
79
84
|
const migration = { migrate: name };
|
|
80
85
|
|
|
81
86
|
relevantProperties.forEach(prop => {
|
|
82
|
-
if (artifact[prop] !== otherArtifact[prop]) {
|
|
83
|
-
changedProperties[prop] = changedElement(artifact[prop], otherArtifact[prop] || null);
|
|
87
|
+
if (artifact[prop.name] !== otherArtifact[prop.name] && (!prop.beta || isBetaEnabled(options, prop.beta))) {
|
|
88
|
+
changedProperties[prop.name] = changedElement(artifact[prop.name], otherArtifact[prop.name] || null);
|
|
84
89
|
}
|
|
85
90
|
});
|
|
86
91
|
if (Object.keys(changedProperties).length > 0) {
|
|
@@ -150,7 +155,7 @@ function isPersistedAsTable(artifact) {
|
|
|
150
155
|
&& !hasAnnotationValue(artifact, '@cds.persistence.exists');
|
|
151
156
|
}
|
|
152
157
|
|
|
153
|
-
function getElementComparator(otherArtifact,
|
|
158
|
+
function getElementComparator(otherArtifact, addedElementsDict = null, changedElementsDict = null) {
|
|
154
159
|
return function compareElements(element, name) {
|
|
155
160
|
if (element._ignore) {
|
|
156
161
|
return;
|
|
@@ -159,19 +164,19 @@ function getElementComparator(otherArtifact, addedElements = null, changedElemen
|
|
|
159
164
|
const otherElement = otherArtifact.elements[name];
|
|
160
165
|
if (otherElement && !otherElement._ignore) {
|
|
161
166
|
// Element type changed?
|
|
162
|
-
if (!
|
|
167
|
+
if (!changedElementsDict) {
|
|
163
168
|
return;
|
|
164
169
|
}
|
|
165
170
|
if (relevantTypeChange(element.type, otherElement.type) || typeParametersChanged(element, otherElement)) {
|
|
166
171
|
// Type or parameters, e.g. association target, changed.
|
|
167
|
-
|
|
172
|
+
changedElementsDict[name] = changedElement(element, otherElement);
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
return;
|
|
171
176
|
}
|
|
172
177
|
|
|
173
|
-
if (
|
|
174
|
-
|
|
178
|
+
if (addedElementsDict) {
|
|
179
|
+
addedElementsDict[name] = element;
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
}
|
package/lib/optionProcessor.js
CHANGED
|
@@ -11,7 +11,9 @@ const optionProcessor = createOptionProcessor();
|
|
|
11
11
|
optionProcessor
|
|
12
12
|
.option('-h, --help')
|
|
13
13
|
.option('-v, --version')
|
|
14
|
+
.option(' --options <file>')
|
|
14
15
|
.option('-w, --warning <level>', ['0', '1', '2', '3'])
|
|
16
|
+
.option(' --quiet')
|
|
15
17
|
.option(' --show-message-id')
|
|
16
18
|
.option(' --no-message-context')
|
|
17
19
|
.option(' --color <mode>', ['auto', 'always', 'never'])
|
|
@@ -22,16 +24,15 @@ optionProcessor
|
|
|
22
24
|
.option(' --trace-parser')
|
|
23
25
|
.option(' --trace-parser-amb')
|
|
24
26
|
.option(' --trace-fs')
|
|
27
|
+
.option(' --error <id-list>')
|
|
28
|
+
.option(' --warn <id-list>')
|
|
29
|
+
.option(' --info <id-list>')
|
|
30
|
+
.option(' --debug <id-list>')
|
|
25
31
|
.option('-E, --enrich-csn')
|
|
26
32
|
.option('-R, --raw-output <name>')
|
|
27
33
|
.option(' --internal-msg')
|
|
28
34
|
.option(' --beta-mode')
|
|
29
35
|
.option(' --beta <list>')
|
|
30
|
-
.option(' --integrity-not-validated')
|
|
31
|
-
.option(' --integrity-not-enforced')
|
|
32
|
-
.option(' --assert-integrity <mode>', [ 'true', 'false', 'individual' ])
|
|
33
|
-
.option(' --assert-integrity-type <type>', [ 'RT', 'DB' ], { ignoreCase: true })
|
|
34
|
-
.option(' --constraints-as-alter <boolean>')
|
|
35
36
|
.option(' --deprecated <list>')
|
|
36
37
|
.option(' --hana-flavor')
|
|
37
38
|
.option(' --direct-backend')
|
|
@@ -59,17 +60,21 @@ optionProcessor
|
|
|
59
60
|
General options
|
|
60
61
|
-h, --help Show this help text
|
|
61
62
|
-v, --version Display version number and exit
|
|
63
|
+
--quiet Don't emit anything, neither results nor messages.
|
|
62
64
|
-w, --warning <level> Show messages up to <level>
|
|
63
65
|
0: Error
|
|
64
66
|
1: Warnings
|
|
65
67
|
2: (default) Info
|
|
66
68
|
3: Debug
|
|
69
|
+
--options <file> Use the given JSON file as input options.
|
|
70
|
+
The key 'cdsc' of 'cds' is used. If not present 'cdsc' is used.
|
|
71
|
+
Otherwise, the JSON as-is is used as options.
|
|
67
72
|
--show-message-id Show message ID in error, warning and info messages
|
|
68
73
|
--no-message-context Print messages as single lines without code context (useful for
|
|
69
|
-
redirecting output to other processes). Default is to print human
|
|
74
|
+
redirecting output to other processes). Default is to print human-
|
|
70
75
|
readable text similar to Rust's compiler with a code excerpt.
|
|
71
76
|
--color <mode> Use colors for warnings. Modes are:
|
|
72
|
-
auto: (default) Detect color support of the
|
|
77
|
+
auto: (default) Detect color support of the TTY.
|
|
73
78
|
always:
|
|
74
79
|
never:
|
|
75
80
|
-o, --out <dir> Place generated files in directory <dir>, default is "-" for <stdout>
|
|
@@ -87,6 +92,13 @@ optionProcessor
|
|
|
87
92
|
--trace-parser-amb Trace parser ambiguities
|
|
88
93
|
--trace-fs Trace file system access caused by "using from"
|
|
89
94
|
|
|
95
|
+
Severity options
|
|
96
|
+
Use these options to reclassify messages. Option argument is a comma separated list of message IDs.
|
|
97
|
+
--error <id-list> IDs that should be reclassified to errors.
|
|
98
|
+
--warn <id-list> IDs that should be reclassified to warnings.
|
|
99
|
+
--info <id-list> IDs that should be reclassified to info messages.
|
|
100
|
+
--debug <id-list> IDs that should be reclassified to debug messages.
|
|
101
|
+
|
|
90
102
|
Internal options (for testing only, may be changed/removed at any time)
|
|
91
103
|
-E, --enrich-csn Show non-enumerable CSN properties and locations of references
|
|
92
104
|
-R, --raw-output <name> Write XSN for definition "name" and error output to <stdout>,
|
|
@@ -99,22 +111,6 @@ optionProcessor
|
|
|
99
111
|
hanaAssocRealCardinality
|
|
100
112
|
mapAssocToJoinCardinality
|
|
101
113
|
ignoreAssocPublishingInUnion
|
|
102
|
-
--integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
|
|
103
|
-
This option is also applied to result of "cdsc manageConstraints"
|
|
104
|
-
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
105
|
-
This option is also applied to result of "cdsc manageConstraints"
|
|
106
|
-
--assert-integrity <mode> Turn DB constraints on/off:
|
|
107
|
-
true : (default) Constraints will be generated for all associations if
|
|
108
|
-
the assert-integrity-type is set to DB
|
|
109
|
-
false : No constraints will be generated
|
|
110
|
-
individual : Constraints will be generated for selected associations
|
|
111
|
-
--assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
|
|
112
|
-
RT : (default) No database constraint for an association
|
|
113
|
-
if not explicitly demanded via annotation
|
|
114
|
-
DB : Create database constraints for associations
|
|
115
|
-
--constraints-as-alter <boolean> If set to 'true', the foreign key constraints will be rendered as
|
|
116
|
-
"ALTER TABLE ADD CONSTRAINT" statement rather than being part of the
|
|
117
|
-
"CREATE TABLE" statement
|
|
118
114
|
--deprecated <list> Comma separated list of deprecated options.
|
|
119
115
|
Valid values are:
|
|
120
116
|
noElementsExpansion
|
|
@@ -124,6 +120,7 @@ optionProcessor
|
|
|
124
120
|
renderVirtualElements
|
|
125
121
|
unmanagedUpInComponent
|
|
126
122
|
createLocalizedViews
|
|
123
|
+
redirectInSubQueries
|
|
127
124
|
--hana-flavor Compile with backward compatibility for HANA CDS (incomplete)
|
|
128
125
|
--parse-only Stop compilation after parsing and write result to <stdout>
|
|
129
126
|
--fallback-parser <type> If the language cannot be deduced by the file's extensions, use this
|
|
@@ -168,6 +165,10 @@ optionProcessor.command('H, toHana')
|
|
|
168
165
|
.option('-u, --user <user>')
|
|
169
166
|
.option('-s, --src')
|
|
170
167
|
.option('-c, --csn')
|
|
168
|
+
.option(' --integrity-not-validated')
|
|
169
|
+
.option(' --integrity-not-enforced')
|
|
170
|
+
.option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
|
|
171
|
+
.option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
|
|
171
172
|
.help(`
|
|
172
173
|
Usage: cdsc toHana [options] <files...>
|
|
173
174
|
|
|
@@ -191,6 +192,17 @@ optionProcessor.command('H, toHana')
|
|
|
191
192
|
-u, --user <user> Value for the "$user" variable
|
|
192
193
|
-s, --src (default) Generate HANA CDS source files "<artifact>.hdbcds"
|
|
193
194
|
-c, --csn Generate "hana_csn.json" with HANA-preprocessed model
|
|
195
|
+
--integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
|
|
196
|
+
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
197
|
+
--assert-integrity <mode> Turn DB constraints on/off:
|
|
198
|
+
true : (default) Constraints will be generated for all associations if
|
|
199
|
+
the assert-integrity-type is set to DB
|
|
200
|
+
false : No constraints will be generated
|
|
201
|
+
individual : Constraints will be generated for selected associations
|
|
202
|
+
--assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
|
|
203
|
+
RT : (default) No database constraint for an association
|
|
204
|
+
if not explicitly demanded via annotation
|
|
205
|
+
DB : Create database constraints for associations
|
|
194
206
|
`);
|
|
195
207
|
|
|
196
208
|
optionProcessor.command('O, toOdata')
|
|
@@ -206,6 +218,7 @@ optionProcessor.command('O, toOdata')
|
|
|
206
218
|
.option('-c, --csn')
|
|
207
219
|
.option('-f, --odata-format <format>', ['flat', 'structured'])
|
|
208
220
|
.option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
|
|
221
|
+
.option('-s, --service-names <list>')
|
|
209
222
|
.help(`
|
|
210
223
|
Usage: cdsc toOdata [options] <files...>
|
|
211
224
|
|
|
@@ -236,6 +249,8 @@ optionProcessor.command('O, toOdata')
|
|
|
236
249
|
but element names flattened with underscores
|
|
237
250
|
hdbcds : Names as HANA CDS would generate them from the same CDS
|
|
238
251
|
source (like "quoted", but using element names with dots)
|
|
252
|
+
-s, --service-names <list> List of comma-separated service names to be rendered
|
|
253
|
+
(default) empty, all services are rendered
|
|
239
254
|
`);
|
|
240
255
|
|
|
241
256
|
optionProcessor.command('C, toCdl')
|
|
@@ -259,6 +274,11 @@ optionProcessor.command('Q, toSql')
|
|
|
259
274
|
.option('-l, --locale <locale>')
|
|
260
275
|
.option('-s, --src <style>', ['sql', 'hdi'])
|
|
261
276
|
.option('-c, --csn')
|
|
277
|
+
.option(' --integrity-not-validated')
|
|
278
|
+
.option(' --integrity-not-enforced')
|
|
279
|
+
.option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
|
|
280
|
+
.option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
|
|
281
|
+
.option(' --constraints-in-create-table')
|
|
262
282
|
.help(`
|
|
263
283
|
Usage: cdsc toSql [options] <files...>
|
|
264
284
|
|
|
@@ -291,6 +311,20 @@ optionProcessor.command('Q, toSql')
|
|
|
291
311
|
the HDI plugin name. Can only be used in combination with
|
|
292
312
|
"hana" dialect.
|
|
293
313
|
-c, --csn Generate "sql_csn.json" with SQL-preprocessed model
|
|
314
|
+
--integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
|
|
315
|
+
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
316
|
+
--assert-integrity <mode> Turn DB constraints on/off:
|
|
317
|
+
true : (default) Constraints will be generated for all associations if
|
|
318
|
+
the assert-integrity-type is set to DB
|
|
319
|
+
false : No constraints will be generated
|
|
320
|
+
individual : Constraints will be generated for selected associations
|
|
321
|
+
--assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
|
|
322
|
+
RT : (default) No database constraint for an association
|
|
323
|
+
if not explicitly demanded via annotation
|
|
324
|
+
DB : Create database constraints for associations
|
|
325
|
+
--constraints-in-create-table If set, the foreign key constraints will be rendered as
|
|
326
|
+
part of the "CREATE TABLE" statements rather than as separate
|
|
327
|
+
"ALTER TABLE ADD CONSTRAINT" statements
|
|
294
328
|
`);
|
|
295
329
|
|
|
296
330
|
optionProcessor.command('toRename')
|
|
@@ -321,13 +355,14 @@ optionProcessor.command('manageConstraints')
|
|
|
321
355
|
.option(' --drop')
|
|
322
356
|
.option(' --alter')
|
|
323
357
|
.option(' --violations')
|
|
358
|
+
.option(' --integrity-not-validated')
|
|
359
|
+
.option(' --integrity-not-enforced')
|
|
324
360
|
.help(`
|
|
325
361
|
Usage: cdsc manageConstraints [options] <files...>
|
|
326
362
|
|
|
327
363
|
(internal, subject to change): Generate SQL DDL ALTER TABLE statements to add / modify
|
|
328
|
-
referential constraints on an existing model.
|
|
329
|
-
|
|
330
|
-
to switch off foreign key constraint enforcement / validation.
|
|
364
|
+
referential constraints on an existing model. This can also be used to
|
|
365
|
+
generate SELECT statements which list all referential integrity violations.
|
|
331
366
|
|
|
332
367
|
Options
|
|
333
368
|
-h, --help Display this help text
|
|
@@ -347,6 +382,8 @@ optionProcessor.command('manageConstraints')
|
|
|
347
382
|
--alter Generate "ALTER TABLE <table> ALTER CONSTRAINT <constraint>" statements
|
|
348
383
|
--violations Generates SELECT statements which can be used to list
|
|
349
384
|
referential integrity violations on the existing data
|
|
385
|
+
--integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
|
|
386
|
+
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
350
387
|
`);
|
|
351
388
|
|
|
352
389
|
optionProcessor.command('toCsn')
|