@sap/cds-compiler 2.11.2 → 2.13.6
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 +175 -2
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +10 -8
- package/bin/cdsc.js +23 -17
- package/bin/cdsse.js +2 -2
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +25 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +32 -79
- package/lib/api/options.js +3 -2
- package/lib/api/validate.js +2 -1
- package/lib/backends.js +16 -26
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +10 -19
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +75 -9
- package/lib/base/messages.js +31 -35
- package/lib/base/model.js +2 -62
- package/lib/base/optionProcessorHelper.js +246 -183
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +2 -1
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/foreignKeys.js +4 -4
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedInType.js +4 -4
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/queryNoDbArtifacts.js +1 -3
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +94 -0
- package/lib/checks/types.js +1 -1
- package/lib/checks/unknownMagic.js +1 -1
- package/lib/checks/validator.js +12 -7
- package/lib/compiler/assert-consistency.js +12 -8
- package/lib/compiler/base.js +0 -1
- package/lib/compiler/builtins.js +42 -21
- package/lib/compiler/checks.js +46 -12
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1103 -0
- package/lib/compiler/extend.js +983 -0
- package/lib/compiler/finalize-parse-cdl.js +231 -0
- package/lib/compiler/index.js +46 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1226 -0
- package/lib/compiler/propagator.js +113 -47
- package/lib/compiler/resolve.js +1433 -0
- package/lib/compiler/shared.js +100 -65
- package/lib/compiler/tweak-assocs.js +529 -0
- package/lib/compiler/utils.js +215 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -25
- package/lib/edm/annotations/preprocessAnnotations.js +3 -3
- package/lib/edm/csn2edm.js +10 -9
- package/lib/edm/edm.js +19 -20
- package/lib/edm/edmPreprocessor.js +166 -95
- package/lib/edm/edmUtils.js +127 -34
- package/lib/gen/Dictionary.json +92 -43
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -82
- package/lib/gen/languageLexer.interp +18 -1
- package/lib/gen/languageLexer.js +925 -847
- package/lib/gen/languageLexer.tokens +78 -74
- package/lib/gen/languageParser.js +5434 -4298
- package/lib/json/from-csn.js +59 -17
- package/lib/json/to-csn.js +189 -71
- package/lib/language/antlrParser.js +3 -3
- package/lib/language/docCommentParser.js +3 -3
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +144 -53
- package/lib/language/language.g4 +424 -200
- package/lib/language/multiLineStringParser.js +536 -0
- package/lib/main.d.ts +550 -61
- package/lib/main.js +38 -11
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +322 -198
- package/lib/model/csnUtils.js +226 -370
- package/lib/model/enrichCsn.js +124 -69
- package/lib/model/revealInternalProperties.js +29 -7
- package/lib/model/sortViews.js +10 -2
- package/lib/modelCompare/compare.js +17 -12
- package/lib/optionProcessor.js +8 -3
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +36 -33
- package/lib/render/toCdl.js +174 -275
- package/lib/render/toHdbcds.js +203 -122
- package/lib/render/toRename.js +7 -10
- package/lib/render/toSql.js +161 -82
- package/lib/render/utils/common.js +22 -8
- package/lib/render/utils/sql.js +10 -7
- 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/braceExpression.js +4 -2
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/db/applyTransformations.js +212 -0
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +187 -0
- package/lib/transform/db/cdsPersistence.js +150 -0
- package/lib/transform/db/constraints.js +61 -56
- package/lib/transform/db/expansion.js +50 -29
- package/lib/transform/db/flattening.js +556 -106
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/temporal.js +236 -0
- package/lib/transform/db/transformExists.js +103 -28
- package/lib/transform/db/views.js +92 -44
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +9 -7
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +98 -783
- package/lib/transform/forOdataNew.js +22 -175
- package/lib/transform/localized.js +36 -32
- package/lib/transform/odata/generateForeignKeyElements.js +3 -3
- package/lib/transform/odata/referenceFlattener.js +95 -89
- package/lib/transform/odata/structureFlattener.js +1 -1
- package/lib/transform/odata/toFinalBaseType.js +86 -12
- package/lib/transform/odata/typesExposure.js +5 -5
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +47 -33
- package/lib/transform/translateAssocsToJoins.js +13 -30
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +170 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/file.js +8 -3
- package/lib/utils/objectUtils.js +30 -0
- package/lib/utils/timetrace.js +8 -2
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/lib/compiler/definer.js +0 -2349
- package/lib/compiler/resolver.js +0 -2922
- package/lib/transform/db/helpers.js +0 -58
- package/lib/transform/universalCsnEnricher.js +0 -67
package/lib/model/enrichCsn.js
CHANGED
|
@@ -7,23 +7,35 @@
|
|
|
7
7
|
|
|
8
8
|
// * `File.cds:3:5` if the original CSN has a non-enumerable `$location` property
|
|
9
9
|
// with value `{file: "File.cds", line: 3, col: 5}`.
|
|
10
|
-
// * `File.cds:3:5
|
|
10
|
+
// * `File.cds:3:5^` if the original CSN has _no_ `$location` property, for an
|
|
11
11
|
// inferred member of a main artifact or member with `$location: `File.cds:3:5`;
|
|
12
|
-
// the number of
|
|
12
|
+
// the number of `^`s in the suffix is the member depth.
|
|
13
13
|
|
|
14
14
|
// Other enumerable properties in the JSON for non-enumerable properties in the
|
|
15
15
|
// original CSN:
|
|
16
16
|
|
|
17
|
-
// * `$
|
|
18
|
-
//
|
|
17
|
+
// * `$parens`: the number of parentheses provided by the user around an expression
|
|
18
|
+
// or query if the number is different to the usual (mostly 0, sometimes 1).
|
|
19
|
+
// * `$elements` (in client-style CSN only) for a non-enumerable `elements` property
|
|
20
|
+
// for sub queries.
|
|
19
21
|
|
|
20
22
|
// The following properties in the JSON represent the result of the CSN API
|
|
21
23
|
// functions:
|
|
22
24
|
|
|
23
|
-
// * `_type`, `_includes` and `_targets` have as values the `$
|
|
25
|
+
// * `_type`, `_includes` and `_targets` have as values the `$location`s of the
|
|
24
26
|
// referred artifacts which are returned by function `artifactRef`.
|
|
25
|
-
// * `_links
|
|
26
|
-
//
|
|
27
|
+
// * `_links` and `_art` as sibling properties of `ref` have as values the
|
|
28
|
+
// `$locations` of the artifacts/members returned by function `inspectRef` (`_art`
|
|
29
|
+
// for ref in `from` only, where it is different to the last item of `_links`).
|
|
30
|
+
// * `_scope` and `_env` as sibling properties of `ref` have (string) values,
|
|
31
|
+
// returned by function `inspectRef`, giving add/ info about the “ref base”.
|
|
32
|
+
// * `_origin` (in Universal CSN only) has as value the `$location` of the
|
|
33
|
+
// prototype returned by function getOrigin().
|
|
34
|
+
// * `_test.inspect.csnpath` as sibling property of `ref` has an object value
|
|
35
|
+
// with properties `_links` and `_scope` of a further `inspectRef` call;
|
|
36
|
+
// it is only called, with `[‹art›, ...‹csnpath›]` as argument, if `‹art›`,
|
|
37
|
+
// which is the referred artifact returned by the first `inspectRef` call,
|
|
38
|
+
// has an annotation `@$test.inspect.csnpath` with array value `‹csnpath›`.
|
|
27
39
|
|
|
28
40
|
'use strict';
|
|
29
41
|
|
|
@@ -32,7 +44,6 @@ const { locationString } = require('../base/location');
|
|
|
32
44
|
|
|
33
45
|
function enrichCsn( csn, options = {} ) {
|
|
34
46
|
const transformers = {
|
|
35
|
-
// $env: reveal,
|
|
36
47
|
elements: dictionary,
|
|
37
48
|
definitions: dictionary,
|
|
38
49
|
actions: dictionary,
|
|
@@ -50,10 +61,14 @@ function enrichCsn( csn, options = {} ) {
|
|
|
50
61
|
// TODO: excluding
|
|
51
62
|
'@': () => { /* ignore annotations */ },
|
|
52
63
|
}
|
|
53
|
-
|
|
54
|
-
const { inspectRef, artifactRef, getOrigin, __getCache_forEnrichCsnDebugging } =
|
|
55
|
-
csnRefs( csn );
|
|
64
|
+
// options.enrichCsn = 'DEBUG';
|
|
56
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
|
+
|
|
57
72
|
const csnPath = [];
|
|
58
73
|
if (csn.definitions)
|
|
59
74
|
dictionary( csn, 'definitions', csn.definitions );
|
|
@@ -84,9 +99,10 @@ function enrichCsn( csn, options = {} ) {
|
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
function definition( parent, prop, obj ) {
|
|
87
|
-
|
|
102
|
+
// call getOrigin() before standard() to set implicit protos inside standard():
|
|
103
|
+
const origin = handleError( err => err ? err.toString() : getOrigin( obj ) );
|
|
88
104
|
standard( parent, prop, obj );
|
|
89
|
-
if (obj.$origin === undefined && origin != null)
|
|
105
|
+
if (obj.$origin === undefined && !obj.type && origin != null)
|
|
90
106
|
obj._origin = refLocation( origin );
|
|
91
107
|
}
|
|
92
108
|
|
|
@@ -95,6 +111,8 @@ function enrichCsn( csn, options = {} ) {
|
|
|
95
111
|
return;
|
|
96
112
|
csnPath.push( prop );
|
|
97
113
|
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
114
|
+
if (prop === 'definitions')
|
|
115
|
+
initDefinition( dict[name] );
|
|
98
116
|
definition( dict, name, dict[name] );
|
|
99
117
|
}
|
|
100
118
|
if (!Object.prototype.propertyIsEnumerable.call( parent, prop ))
|
|
@@ -103,11 +121,19 @@ function enrichCsn( csn, options = {} ) {
|
|
|
103
121
|
}
|
|
104
122
|
|
|
105
123
|
function refLocation( art ) {
|
|
106
|
-
if (art)
|
|
107
|
-
|
|
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
|
+
|
|
108
134
|
if (!options.testMode)
|
|
109
|
-
return
|
|
110
|
-
throw new Error( '
|
|
135
|
+
return `<${Object.keys( art ).join('+')}+!$location>`;
|
|
136
|
+
throw new Error( 'Reference to object without $location' );
|
|
111
137
|
}
|
|
112
138
|
|
|
113
139
|
function simpleRef( parent, prop, ref ) {
|
|
@@ -133,37 +159,21 @@ function enrichCsn( csn, options = {} ) {
|
|
|
133
159
|
}
|
|
134
160
|
|
|
135
161
|
function $origin( parent, prop, ref ) {
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
parent._origin =
|
|
139
|
-
else if ( ref )
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (Array.isArray( ref ) || typeof ref === 'string') // $origin: […], not $origin: {…}
|
|
145
|
-
parent._origin = refLocation( getOrigin( parent, true ) );
|
|
146
|
-
else if ( ref )
|
|
147
|
-
standard( parent, prop, ref )
|
|
148
|
-
} catch (e) {
|
|
149
|
-
parent._origin = e.toString();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
162
|
+
handleError( err => {
|
|
163
|
+
if (err)
|
|
164
|
+
parent._origin = err.toString();
|
|
165
|
+
else if (Array.isArray( ref ) || typeof ref === 'string') // $origin: […] / "short-ref"
|
|
166
|
+
parent._origin = refLocation( getOrigin( parent ) );
|
|
167
|
+
else if ( ref ) // $origin: {…}
|
|
168
|
+
standard( parent, prop, ref );
|
|
169
|
+
} );
|
|
152
170
|
}
|
|
153
171
|
|
|
154
|
-
function pathRef( parent, prop, path ) {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
return inspectRef( csnPath );
|
|
161
|
-
}
|
|
162
|
-
catch (e) {
|
|
163
|
-
return { scope: e.toString() };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
} )();
|
|
172
|
+
function pathRef( parent, prop, path, inspectionPath = csnPath ) {
|
|
173
|
+
const inspection = handleError( (err) => {
|
|
174
|
+
return (err) ? { scope: err.toString() } : inspectRef( inspectionPath );
|
|
175
|
+
});
|
|
176
|
+
const { links, art, scope, $env } = inspection;
|
|
167
177
|
if (links)
|
|
168
178
|
parent._links = links.map( l => refLocation( l.art ) );
|
|
169
179
|
if (links && links[links.length-1].art !== art)
|
|
@@ -172,6 +182,15 @@ function enrichCsn( csn, options = {} ) {
|
|
|
172
182
|
if ($env)
|
|
173
183
|
parent._env = $env;
|
|
174
184
|
|
|
185
|
+
if (!prop) // recursive call for @$test.inspect.csnpath
|
|
186
|
+
return;
|
|
187
|
+
const testPath = art && art['@$test.inspect.csnpath'];
|
|
188
|
+
if (testPath && parent.ref) {
|
|
189
|
+
const further = {};
|
|
190
|
+
pathRef( further, null, null, [ inspection, ...testPath ] );
|
|
191
|
+
parent['_test.inspect.csnpath'] = further;
|
|
192
|
+
}
|
|
193
|
+
|
|
175
194
|
csnPath.push( prop );
|
|
176
195
|
path.forEach( function step( s, i ) {
|
|
177
196
|
if (s && typeof s === 'object') {
|
|
@@ -186,6 +205,16 @@ function enrichCsn( csn, options = {} ) {
|
|
|
186
205
|
csnPath.pop();
|
|
187
206
|
}
|
|
188
207
|
|
|
208
|
+
function handleError( callback ) {
|
|
209
|
+
if (options.testMode)
|
|
210
|
+
return callback();
|
|
211
|
+
try {
|
|
212
|
+
return callback();
|
|
213
|
+
} catch (err) {
|
|
214
|
+
return callback( err );
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
189
218
|
function _cache_debug( obj, subCache ) {
|
|
190
219
|
if (options.enrichCsn !== 'DEBUG')
|
|
191
220
|
return;
|
|
@@ -227,6 +256,10 @@ function enrichCsn( csn, options = {} ) {
|
|
|
227
256
|
obj.$$cacheObject[name] = sub;
|
|
228
257
|
}
|
|
229
258
|
}
|
|
259
|
+
else if (name === '$origin$step') { // string value handled above
|
|
260
|
+
const kind = Object.keys( val )[0];
|
|
261
|
+
obj.$$cacheObject[name] = `${kind}: ${ val[kind] }`;
|
|
262
|
+
}
|
|
230
263
|
else if (Array.isArray( val )) {
|
|
231
264
|
obj.$$cacheObject[name] = val.map( item => {
|
|
232
265
|
if (!item.$$objectNumber)
|
|
@@ -242,8 +275,53 @@ function enrichCsn( csn, options = {} ) {
|
|
|
242
275
|
}
|
|
243
276
|
}
|
|
244
277
|
}
|
|
278
|
+
|
|
279
|
+
function debugLocation( loc, userProvided ) {
|
|
280
|
+
if (debugLocationInfo && !userProvided) {
|
|
281
|
+
loc = loc.replace( /\([0-9]+\)\^/, '^' );
|
|
282
|
+
debugLocationInfo[loc] = (debugLocationInfo[loc] || 0) + 1;
|
|
283
|
+
loc = `${loc}(${debugLocationInfo[loc]})`;
|
|
284
|
+
}
|
|
285
|
+
return loc;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function setLocations( node, prop, loc ) {
|
|
289
|
+
if (!node || typeof node !== 'object')
|
|
290
|
+
return;
|
|
291
|
+
const isMember = artifactProperties.includes( prop );
|
|
292
|
+
if (!isMember && node.$location) {
|
|
293
|
+
if (typeof node.$location === 'string') // already set for nested 'items'
|
|
294
|
+
return;
|
|
295
|
+
loc = locationString( node.$location, true );
|
|
296
|
+
if (!node.SELECT) // compatibility: $location of query both inside and as sibling of SELECT
|
|
297
|
+
reveal( node, '$location', debugLocation( loc, !node.$generated ) );
|
|
298
|
+
}
|
|
299
|
+
else if (prop === true || prop === 'returns') { // in dictionary or returns
|
|
300
|
+
loc = debugLocation( loc + '^' );
|
|
301
|
+
node.$location = loc;
|
|
302
|
+
}
|
|
303
|
+
else if (prop === 'items') {
|
|
304
|
+
let iloc = loc + '[]';
|
|
305
|
+
let obj = node;
|
|
306
|
+
while (obj) {
|
|
307
|
+
// should not appear in --enrich-csn, only for _origin info
|
|
308
|
+
Object.defineProperty( obj, '$location', { value: iloc, enumerable: false } );
|
|
309
|
+
obj = obj.items;
|
|
310
|
+
iloc += '[]';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray( node )) {
|
|
314
|
+
for (const item of node)
|
|
315
|
+
setLocations( item, isMember, loc );
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
for (const name of Object.getOwnPropertyNames( node ))
|
|
319
|
+
setLocations( node[name], isMember || name, loc );
|
|
320
|
+
}
|
|
321
|
+
}
|
|
245
322
|
}
|
|
246
323
|
|
|
324
|
+
|
|
247
325
|
function reveal( node, prop, value ) {
|
|
248
326
|
Object.defineProperty( node, prop, {
|
|
249
327
|
value,
|
|
@@ -253,27 +331,4 @@ function reveal( node, prop, value ) {
|
|
|
253
331
|
} );
|
|
254
332
|
}
|
|
255
333
|
|
|
256
|
-
function setLocations( node, prop, loc ) {
|
|
257
|
-
if (!node || typeof node !== 'object')
|
|
258
|
-
return;
|
|
259
|
-
const isMember = artifactProperties.includes( prop );
|
|
260
|
-
if (!isMember && node.$location) {
|
|
261
|
-
const value = locationString( node.$location, true );
|
|
262
|
-
reveal( node, '$location', value );
|
|
263
|
-
loc = value + '-';
|
|
264
|
-
}
|
|
265
|
-
else if (prop === true) {
|
|
266
|
-
loc += '1';
|
|
267
|
-
node.$location = loc;
|
|
268
|
-
}
|
|
269
|
-
if (Array.isArray( node )) {
|
|
270
|
-
for (const item of node)
|
|
271
|
-
setLocations( item, isMember, loc );
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
for (const name of Object.getOwnPropertyNames( node ))
|
|
275
|
-
setLocations( node[name], isMember || name, loc );
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
334
|
module.exports = enrichCsn;
|
|
@@ -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
|
//
|
|
@@ -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
|
}
|
|
@@ -271,12 +287,15 @@ function artifactIdentifier( node, parent ) {
|
|
|
271
287
|
Object.defineProperty( node, '__unique_id__', { value: ++unique_id } );
|
|
272
288
|
let outer = unique_id ? '##' + node.__unique_id__ : '';
|
|
273
289
|
if (node._outer) {
|
|
274
|
-
|
|
275
|
-
|
|
290
|
+
if (node.$inferred === 'REDIRECTED')
|
|
291
|
+
outer = '/redirected' + outer;
|
|
292
|
+
else
|
|
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;
|
|
276
297
|
node = node._outer;
|
|
277
298
|
}
|
|
278
|
-
else if (node.$inferred === 'REDIRECTED')
|
|
279
|
-
outer = '/redirected';
|
|
280
299
|
if (node === parent)
|
|
281
300
|
return 'this';
|
|
282
301
|
if (node.kind === 'source')
|
|
@@ -304,7 +323,10 @@ function artifactIdentifier( node, parent ) {
|
|
|
304
323
|
return 'source:' + quoted( node.location && node.location.file ) +
|
|
305
324
|
'/using:' + quoted( node.name.id )
|
|
306
325
|
default: {
|
|
307
|
-
|
|
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;
|
|
308
330
|
}
|
|
309
331
|
}
|
|
310
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
|
|
@@ -79,7 +80,7 @@ function sortTopologically(csn, _dependents, _dependencies){
|
|
|
79
80
|
/**
|
|
80
81
|
* Sort the given sql statements so that they can be deployed sequentially.
|
|
81
82
|
* For ordering, only the FROM clause of views is checked - this requires A2J to
|
|
82
|
-
* be run beforehand to
|
|
83
|
+
* be run beforehand to resolve association usages.
|
|
83
84
|
*
|
|
84
85
|
* @param {object} sql Map of <object name>: "CREATE STATEMENT"
|
|
85
86
|
*
|
|
@@ -91,10 +92,17 @@ 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
|
|
98
99
|
layers.forEach(layer => layer.forEach(objName => result.push({name: objName, sql: sql[objName]})));
|
|
100
|
+
// attach sql artifacts which are not considered during the view sorting algorithm
|
|
101
|
+
// --> this is the case for "ALTER TABLE ADD CONSTRAINT" statements,
|
|
102
|
+
// because their identifiers are not part of the csn.definitions
|
|
103
|
+
Object.entries(sql).forEach(([ name, sqlString ]) => {
|
|
104
|
+
if (!result.some( o => o.name === name )) // not in result but in incoming sql
|
|
105
|
+
result.push({ name, sql: sqlString })
|
|
106
|
+
});
|
|
99
107
|
return result;
|
|
100
108
|
}
|
|
@@ -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;
|
|
@@ -60,7 +61,7 @@ function validateCsnVersions(beforeModel, afterModel, options) {
|
|
|
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
|
@@ -30,7 +30,8 @@ optionProcessor
|
|
|
30
30
|
.option(' --integrity-not-validated')
|
|
31
31
|
.option(' --integrity-not-enforced')
|
|
32
32
|
.option(' --assert-integrity <mode>', [ 'true', 'false', 'individual' ])
|
|
33
|
-
.option(' --assert-integrity-type <type>', [ 'RT', 'DB' ])
|
|
33
|
+
.option(' --assert-integrity-type <type>', [ 'RT', 'DB' ], { ignoreCase: true })
|
|
34
|
+
.option(' --constraints-in-create-table')
|
|
34
35
|
.option(' --deprecated <list>')
|
|
35
36
|
.option(' --hana-flavor')
|
|
36
37
|
.option(' --direct-backend')
|
|
@@ -103,14 +104,17 @@ optionProcessor
|
|
|
103
104
|
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
104
105
|
This option is also applied to result of "cdsc manageConstraints"
|
|
105
106
|
--assert-integrity <mode> Turn DB constraints on/off:
|
|
106
|
-
true : Constraints will be generated for all associations if
|
|
107
|
+
true : (default) Constraints will be generated for all associations if
|
|
107
108
|
the assert-integrity-type is set to DB
|
|
108
109
|
false : No constraints will be generated
|
|
109
110
|
individual : Constraints will be generated for selected associations
|
|
110
111
|
--assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
|
|
111
112
|
RT : (default) No database constraint for an association
|
|
112
113
|
if not explicitly demanded via annotation
|
|
113
|
-
DB : Create database constraints for associations
|
|
114
|
+
DB : Create database constraints for associations
|
|
115
|
+
--constraints-in-create-table If set, the foreign key constraints will be rendered as
|
|
116
|
+
part of the "CREATE TABLE" statements rather than as separate
|
|
117
|
+
"ALTER TABLE ADD CONSTRAINT" statements
|
|
114
118
|
--deprecated <list> Comma separated list of deprecated options.
|
|
115
119
|
Valid values are:
|
|
116
120
|
noElementsExpansion
|
|
@@ -120,6 +124,7 @@ optionProcessor
|
|
|
120
124
|
renderVirtualElements
|
|
121
125
|
unmanagedUpInComponent
|
|
122
126
|
createLocalizedViews
|
|
127
|
+
redirectInSubQueries
|
|
123
128
|
--hana-flavor Compile with backward compatibility for HANA CDS (incomplete)
|
|
124
129
|
--parse-only Stop compilation after parsing and write result to <stdout>
|
|
125
130
|
--fallback-parser <type> If the language cannot be deduced by the file's extensions, use this
|