@sap/cds-compiler 2.10.2 → 2.11.4
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 +90 -5
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +3 -1
- package/bin/cdsc.js +49 -25
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_BETA.md +10 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +8 -36
- package/lib/api/options.js +15 -6
- package/lib/api/validate.js +30 -3
- package/lib/backends.js +12 -13
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +3 -2
- package/lib/base/message-registry.js +34 -10
- package/lib/base/messages.js +38 -18
- package/lib/base/model.js +5 -4
- package/lib/base/optionProcessorHelper.js +57 -23
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/unknownMagic.js +6 -3
- package/lib/compiler/assert-consistency.js +9 -2
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +62 -16
- package/lib/compiler/checks.js +2 -1
- package/lib/compiler/definer.js +66 -108
- package/lib/compiler/index.js +29 -29
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +225 -58
- package/lib/compiler/shared.js +53 -229
- package/lib/compiler/utils.js +184 -0
- package/lib/edm/annotations/genericTranslation.js +1 -1
- package/lib/edm/csn2edm.js +3 -2
- package/lib/edm/edmPreprocessor.js +34 -38
- package/lib/edm/edmUtils.js +3 -3
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +17 -1
- package/lib/gen/language.tokens +79 -73
- package/lib/gen/languageLexer.interp +19 -1
- package/lib/gen/languageLexer.js +779 -731
- package/lib/gen/languageLexer.tokens +71 -65
- package/lib/gen/languageParser.js +4668 -4072
- package/lib/json/from-csn.js +10 -10
- package/lib/json/to-csn.js +228 -47
- package/lib/language/antlrParser.js +11 -0
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +73 -14
- package/lib/language/language.g4 +79 -3
- package/lib/main.d.ts +215 -18
- package/lib/main.js +3 -1
- package/lib/model/api.js +2 -2
- package/lib/model/csnRefs.js +117 -33
- package/lib/model/csnUtils.js +65 -133
- package/lib/model/enrichCsn.js +62 -37
- package/lib/model/revealInternalProperties.js +25 -8
- package/lib/model/sortViews.js +8 -1
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +33 -18
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/toCdl.js +15 -8
- package/lib/render/toHdbcds.js +26 -49
- package/lib/render/toSql.js +61 -39
- package/lib/render/utils/common.js +1 -1
- package/lib/transform/db/applyTransformations.js +189 -0
- package/lib/transform/db/constraints.js +273 -119
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +6 -4
- package/lib/transform/db/flattening.js +19 -3
- package/lib/transform/db/transformExists.js +102 -9
- package/lib/transform/db/views.js +485 -0
- package/lib/transform/forHanaNew.js +93 -448
- package/lib/transform/forOdataNew.js +9 -2
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/structuralPath.js +1 -5
- package/lib/transform/transformUtilsNew.js +22 -8
- package/lib/transform/translateAssocsToJoins.js +7 -15
- package/lib/utils/file.js +11 -5
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
- package/lib/transform/db/helpers.js +0 -58
package/lib/model/enrichCsn.js
CHANGED
|
@@ -14,16 +14,22 @@
|
|
|
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`.
|
|
29
|
+
// * `_scope` and `_env` as sibling properties of `ref` have (string) values,
|
|
30
|
+
// returned by function `inspectRef`, giving add/ info about the “ref base”.
|
|
31
|
+
// * `_origin` (in Universal CSN only) has as value the `$location` of the
|
|
32
|
+
// prototype returned by function getOrigin().
|
|
27
33
|
|
|
28
34
|
'use strict';
|
|
29
35
|
|
|
@@ -32,13 +38,14 @@ const { locationString } = require('../base/location');
|
|
|
32
38
|
|
|
33
39
|
function enrichCsn( csn, options = {} ) {
|
|
34
40
|
const transformers = {
|
|
35
|
-
// $env: reveal,
|
|
36
41
|
elements: dictionary,
|
|
37
42
|
definitions: dictionary,
|
|
38
43
|
actions: dictionary,
|
|
39
44
|
params: dictionary,
|
|
40
45
|
enum: dictionary,
|
|
41
46
|
mixin: dictionary,
|
|
47
|
+
returns: definition,
|
|
48
|
+
items: definition,
|
|
42
49
|
ref: pathRef,
|
|
43
50
|
type: simpleRef,
|
|
44
51
|
targetAspect: simpleRef,
|
|
@@ -81,10 +88,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
81
88
|
csnPath.pop();
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
function definition( parent, prop, obj ) {
|
|
92
|
+
// call getOrigin() before standard() to set implicit protos inside standard():
|
|
93
|
+
const origin = handleError( err => err ? err.toString() : getOrigin( obj ) );
|
|
94
|
+
standard( parent, prop, obj );
|
|
95
|
+
if (obj.$origin === undefined && origin != null)
|
|
96
|
+
obj._origin = refLocation( origin );
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
function dictionary( parent, prop, dict ) {
|
|
100
|
+
if (!dict) // value null for inheritance interruption
|
|
101
|
+
return;
|
|
85
102
|
csnPath.push( prop );
|
|
86
103
|
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
87
|
-
|
|
104
|
+
definition( dict, name, dict[name] );
|
|
88
105
|
}
|
|
89
106
|
if (!Object.prototype.propertyIsEnumerable.call( parent, prop ))
|
|
90
107
|
parent['$'+prop] = dict;
|
|
@@ -92,10 +109,10 @@ function enrichCsn( csn, options = {} ) {
|
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
function refLocation( art ) {
|
|
95
|
-
if (art)
|
|
112
|
+
if (art && typeof art === 'object')
|
|
96
113
|
return art.$location || '<no location>';
|
|
97
114
|
if (!options.testMode)
|
|
98
|
-
return '<illegal link>';
|
|
115
|
+
return art || '<illegal link>';
|
|
99
116
|
throw new Error( 'Undefined reference' );
|
|
100
117
|
}
|
|
101
118
|
|
|
@@ -122,33 +139,19 @@ function enrichCsn( csn, options = {} ) {
|
|
|
122
139
|
}
|
|
123
140
|
|
|
124
141
|
function $origin( parent, prop, ref ) {
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
parent._origin =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
} catch (e) {
|
|
134
|
-
parent._origin = e.toString();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
142
|
+
handleError( err => {
|
|
143
|
+
if (err)
|
|
144
|
+
parent._origin = err.toString();
|
|
145
|
+
else if (Array.isArray( ref ) || typeof ref === 'string') // $origin: […], not $origin: {…}
|
|
146
|
+
parent._origin = refLocation( getOrigin( parent, true ) );
|
|
147
|
+
else if ( ref )
|
|
148
|
+
standard( parent, prop, ref );
|
|
149
|
+
} );
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
function pathRef( parent, prop, path ) {
|
|
140
|
-
const { links, art, scope, $env }
|
|
141
|
-
|
|
142
|
-
return inspectRef( csnPath );
|
|
143
|
-
else {
|
|
144
|
-
try {
|
|
145
|
-
return inspectRef( csnPath );
|
|
146
|
-
}
|
|
147
|
-
catch (e) {
|
|
148
|
-
return { scope: e.toString() };
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} )();
|
|
153
|
+
const { links, art, scope, $env }
|
|
154
|
+
= handleError( err => (err) ? { scope: err.toString() } : inspectRef( csnPath ) );
|
|
152
155
|
if (links)
|
|
153
156
|
parent._links = links.map( l => refLocation( l.art ) );
|
|
154
157
|
if (links && links[links.length-1].art !== art)
|
|
@@ -171,10 +174,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
171
174
|
csnPath.pop();
|
|
172
175
|
}
|
|
173
176
|
|
|
174
|
-
function
|
|
177
|
+
function handleError( callback ) {
|
|
178
|
+
if (options.testMode)
|
|
179
|
+
return callback();
|
|
180
|
+
try {
|
|
181
|
+
return callback();
|
|
182
|
+
} catch (err) {
|
|
183
|
+
return callback( err );
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function _cache_debug( obj, subCache ) {
|
|
175
188
|
if (options.enrichCsn !== 'DEBUG')
|
|
176
189
|
return;
|
|
177
|
-
const cache = __getCache_forEnrichCsnDebugging( obj );
|
|
190
|
+
const cache = subCache || __getCache_forEnrichCsnDebugging( obj );
|
|
178
191
|
if (!cache)
|
|
179
192
|
return;
|
|
180
193
|
if (cache.$$objectNumber > 0) {
|
|
@@ -197,8 +210,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
197
210
|
}
|
|
198
211
|
else if (name[0] !== '$' || !Object.getPrototypeOf( val )) {
|
|
199
212
|
// ‹name›: dictionary of CSN nodes,
|
|
200
|
-
// ‹$name›: dictionary of cache values if no prototype
|
|
201
|
-
|
|
213
|
+
// ‹$name›: dictionary of cache values if no prototype
|
|
214
|
+
if (name !== '$aliases') {
|
|
215
|
+
obj.$$cacheObject[name] = Object.keys( val ); // TODO: or dict?
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const sub = Object.create(null);
|
|
219
|
+
for (const n in val) {
|
|
220
|
+
const alias = val[n];
|
|
221
|
+
const c = {};
|
|
222
|
+
_cache_debug( c, alias );
|
|
223
|
+
sub[n] = c.$$cacheObject;
|
|
224
|
+
}
|
|
225
|
+
obj.$$cacheObject[name] = sub;
|
|
226
|
+
}
|
|
202
227
|
}
|
|
203
228
|
else if (Array.isArray( val )) {
|
|
204
229
|
obj.$$cacheObject[name] = val.map( item => {
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
const msg = require('../base/messages');
|
|
15
15
|
|
|
16
|
+
const $inferred = Symbol.for('cds.$inferred');
|
|
17
|
+
|
|
16
18
|
class NOT_A_DICTIONARY {} // used for consol.log display
|
|
17
19
|
|
|
18
20
|
function locationString( loc ) {
|
|
@@ -32,15 +34,22 @@ const kindsRepresentedAsLinks = {
|
|
|
32
34
|
// represent SELECTs in query / SET-args property as link:
|
|
33
35
|
select: (art, parent) => art._main && parent !== art._main.$queries,
|
|
34
36
|
// represent table alias in from / join-args property as link:
|
|
35
|
-
$tableAlias:
|
|
36
|
-
// represent
|
|
37
|
+
$tableAlias: tableAliasAsLink,
|
|
38
|
+
// represent "navigation elemens" in _combined as links:
|
|
37
39
|
$navElement: (art, parent) => art._parent && parent !== art._parent.elements,
|
|
38
40
|
// represent mixin in $tableAliases as link:
|
|
39
|
-
mixin:
|
|
41
|
+
mixin: tableAliasAsLink,
|
|
40
42
|
// represent $projection as link, as it is just another search name for $self:
|
|
41
43
|
$self: (_a, _p, name) => name !== '$self',
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
function tableAliasAsLink( art, parent, name ) {
|
|
47
|
+
return art._parent && art._parent.$tableAliases && // initXYZ() is run
|
|
48
|
+
parent !== art._parent.$tableAliases && // not in $tableAliases
|
|
49
|
+
!(art.$duplicates === true && name && // and its $duplicates
|
|
50
|
+
parent === art._parent.$tableAliases[name].$duplicates);
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
function revealInternalProperties( model, name ) {
|
|
45
54
|
const transformers = {
|
|
46
55
|
messages: m => m,
|
|
@@ -65,6 +74,7 @@ function revealInternalProperties( model, name ) {
|
|
|
65
74
|
mixin: dictionary,
|
|
66
75
|
args: dictionary,
|
|
67
76
|
$tableAliases: dictionary,
|
|
77
|
+
$duplicates: duplicates,
|
|
68
78
|
$keysNavigation: dictionary,
|
|
69
79
|
$layerNumber: n => n,
|
|
70
80
|
$extra: e => e,
|
|
@@ -203,6 +213,8 @@ function revealInternalProperties( model, name ) {
|
|
|
203
213
|
for (let prop of Object.getOwnPropertyNames( node )) { // also non-enumerable
|
|
204
214
|
r[prop] = reveal( node[prop], node, prop );
|
|
205
215
|
}
|
|
216
|
+
if (node[$inferred] && !node['[$inferred]'])
|
|
217
|
+
r['[$inferred]'] = node[$inferred];
|
|
206
218
|
return r;
|
|
207
219
|
}
|
|
208
220
|
|
|
@@ -228,7 +240,7 @@ function revealInternalProperties( model, name ) {
|
|
|
228
240
|
if (node == null || typeof node !== 'object' )
|
|
229
241
|
return node
|
|
230
242
|
if (Array.isArray(node))
|
|
231
|
-
return node.map( n => reveal( n, node ) );
|
|
243
|
+
return node.map( n => reveal( n, node, name ) );
|
|
232
244
|
|
|
233
245
|
const asLinkTest = kindsRepresentedAsLinks[ node.kind ];
|
|
234
246
|
if (asLinkTest && asLinkTest( node, parent, name ))
|
|
@@ -246,6 +258,10 @@ function revealInternalProperties( model, name ) {
|
|
|
246
258
|
}
|
|
247
259
|
return r;
|
|
248
260
|
}
|
|
261
|
+
|
|
262
|
+
function duplicates( node, parent ) {
|
|
263
|
+
return reveal( node, parent, parent.name && parent.name.id );
|
|
264
|
+
}
|
|
249
265
|
}
|
|
250
266
|
|
|
251
267
|
function artifactIdentifier( node, parent ) {
|
|
@@ -255,12 +271,13 @@ function artifactIdentifier( node, parent ) {
|
|
|
255
271
|
Object.defineProperty( node, '__unique_id__', { value: ++unique_id } );
|
|
256
272
|
let outer = unique_id ? '##' + node.__unique_id__ : '';
|
|
257
273
|
if (node._outer) {
|
|
258
|
-
|
|
259
|
-
|
|
274
|
+
if (node.$inferred === 'REDIRECTED')
|
|
275
|
+
outer = '/redirected';
|
|
276
|
+
else
|
|
277
|
+
outer = (node._outer.items === node) ? '/items'
|
|
278
|
+
: (node._outer.returns === node) ? '/returns' : '/returns/items';
|
|
260
279
|
node = node._outer;
|
|
261
280
|
}
|
|
262
|
-
else if (node.$inferred === 'REDIRECTED')
|
|
263
|
-
outer = '/redirected';
|
|
264
281
|
if (node === parent)
|
|
265
282
|
return 'this';
|
|
266
283
|
if (node.kind === 'source')
|
package/lib/model/sortViews.js
CHANGED
|
@@ -79,7 +79,7 @@ function sortTopologically(csn, _dependents, _dependencies){
|
|
|
79
79
|
/**
|
|
80
80
|
* Sort the given sql statements so that they can be deployed sequentially.
|
|
81
81
|
* For ordering, only the FROM clause of views is checked - this requires A2J to
|
|
82
|
-
* be run beforehand to
|
|
82
|
+
* be run beforehand to resolve association usages.
|
|
83
83
|
*
|
|
84
84
|
* @param {object} sql Map of <object name>: "CREATE STATEMENT"
|
|
85
85
|
*
|
|
@@ -96,5 +96,12 @@ module.exports = function({sql, csn}){
|
|
|
96
96
|
const result = [];
|
|
97
97
|
// keep the "artifact name" - needed for to.hdi sorting
|
|
98
98
|
layers.forEach(layer => layer.forEach(objName => result.push({name: objName, sql: sql[objName]})));
|
|
99
|
+
// attach sql artifacts which are not considered during the view sorting algorithm
|
|
100
|
+
// --> this is the case for "ALTER TABLE ADD CONSTRAINT" statements,
|
|
101
|
+
// because their identifiers are not part of the csn.definitions
|
|
102
|
+
Object.entries(sql).forEach(([ name, sqlString ]) => {
|
|
103
|
+
if (!result.some( o => o.name === name )) // not in result but in incoming sql
|
|
104
|
+
result.push({ name, sql: sqlString })
|
|
105
|
+
});
|
|
99
106
|
return result;
|
|
100
107
|
}
|
|
@@ -12,11 +12,12 @@ const {
|
|
|
12
12
|
*
|
|
13
13
|
* @param beforeModel the before-model
|
|
14
14
|
* @param afterModel the after-model
|
|
15
|
-
* @param {hdiOptions|false} options
|
|
15
|
+
* @param {import('../api/main.js').hdiOptions|false} options
|
|
16
16
|
* @returns {object} the sets of deletions, extensions, and migrations of entities necessary to transform the before-model
|
|
17
17
|
* to the after-model, together with all the definitions of the after-model
|
|
18
18
|
*/
|
|
19
19
|
function compareModels(beforeModel, afterModel, options) {
|
|
20
|
+
// @ts-ignore
|
|
20
21
|
if(!(options && options.testMode)) // no $version with testMode
|
|
21
22
|
validateCsnVersions(beforeModel, afterModel, options);
|
|
22
23
|
|
package/lib/optionProcessor.js
CHANGED
|
@@ -27,8 +27,11 @@ optionProcessor
|
|
|
27
27
|
.option(' --internal-msg')
|
|
28
28
|
.option(' --beta-mode')
|
|
29
29
|
.option(' --beta <list>')
|
|
30
|
-
.option(' --
|
|
31
|
-
.option(' --
|
|
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' ])
|
|
34
|
+
.option(' --constraints-as-alter <boolean>')
|
|
32
35
|
.option(' --deprecated <list>')
|
|
33
36
|
.option(' --hana-flavor')
|
|
34
37
|
.option(' --direct-backend')
|
|
@@ -39,7 +42,8 @@ optionProcessor
|
|
|
39
42
|
.option(' --doc-comment')
|
|
40
43
|
.option(' --add-texts-language-assoc')
|
|
41
44
|
.option(' --localized-without-coalesce')
|
|
42
|
-
.option(' --
|
|
45
|
+
.option(' --default-binary-length <length>')
|
|
46
|
+
.option(' --default-string-length <length>')
|
|
43
47
|
.option(' --no-recompile')
|
|
44
48
|
.positionalArgument('<files...>')
|
|
45
49
|
.help(`
|
|
@@ -75,7 +79,8 @@ optionProcessor
|
|
|
75
79
|
-- Indicate the end of options (helpful if source names start with "-")
|
|
76
80
|
|
|
77
81
|
Type options
|
|
78
|
-
--
|
|
82
|
+
--default-binary-length <length> Default 'length' for 'cds.Binary'
|
|
83
|
+
--default-string-length <length> Default 'length' for 'cds.String'
|
|
79
84
|
|
|
80
85
|
Diagnostic options
|
|
81
86
|
--trace-parser Trace parser
|
|
@@ -90,16 +95,26 @@ optionProcessor
|
|
|
90
95
|
--beta-mode Enable all unsupported, incomplete (beta) features
|
|
91
96
|
--beta <list> Comma separated list of unsupported, incomplete (beta) features to use.
|
|
92
97
|
Valid values are:
|
|
93
|
-
foreignKeyConstraints
|
|
94
98
|
addTextsLanguageAssoc
|
|
95
99
|
hanaAssocRealCardinality
|
|
96
100
|
mapAssocToJoinCardinality
|
|
97
101
|
ignoreAssocPublishingInUnion
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 : 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
|
|
103
118
|
--deprecated <list> Comma separated list of deprecated options.
|
|
104
119
|
Valid values are:
|
|
105
120
|
noElementsExpansion
|
|
@@ -130,7 +145,7 @@ optionProcessor
|
|
|
130
145
|
to "sap.common.Languages" if it exists
|
|
131
146
|
--localized-without-coalesce Omit coalesce in localized convenience views
|
|
132
147
|
--no-recompile Don't recompile in case of internal errors
|
|
133
|
-
|
|
148
|
+
|
|
134
149
|
Commands
|
|
135
150
|
H, toHana [options] <files...> Generate HANA CDS source files
|
|
136
151
|
O, toOdata [options] <files...> Generate ODATA metadata and annotations
|
|
@@ -140,7 +155,7 @@ optionProcessor
|
|
|
140
155
|
parseCdl [options] <file> Generate a CSN that is close to the CDL source.
|
|
141
156
|
explain <message-id> Explain a compiler message.
|
|
142
157
|
toRename [options] <files...> (internal) Generate SQL DDL rename statements
|
|
143
|
-
manageConstraints [options] <files...>
|
|
158
|
+
manageConstraints [options] <files...> (internal) Generate ALTER TABLE statements to
|
|
144
159
|
add / modify referential constraints.
|
|
145
160
|
`);
|
|
146
161
|
|
|
@@ -150,7 +165,6 @@ optionProcessor.command('H, toHana')
|
|
|
150
165
|
.option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
|
|
151
166
|
.option(' --render-virtual')
|
|
152
167
|
.option(' --joinfk')
|
|
153
|
-
.option(' --skip-db-constraints')
|
|
154
168
|
.option('-u, --user <user>')
|
|
155
169
|
.option('-s, --src')
|
|
156
170
|
.option('-c, --csn')
|
|
@@ -174,7 +188,6 @@ optionProcessor.command('H, toHana')
|
|
|
174
188
|
using element names with dots).
|
|
175
189
|
--render-virtual Render virtual elements in views and draft tables
|
|
176
190
|
--joinfk Create JOINs for foreign key accesses
|
|
177
|
-
--skip-db-constraints Do not render referential constraints for associations
|
|
178
191
|
-u, --user <user> Value for the "$user" variable
|
|
179
192
|
-s, --src (default) Generate HANA CDS source files "<artifact>.hdbcds"
|
|
180
193
|
-c, --csn Generate "hana_csn.json" with HANA-preprocessed model
|
|
@@ -241,7 +254,6 @@ optionProcessor.command('Q, toSql')
|
|
|
241
254
|
.option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
|
|
242
255
|
.option(' --render-virtual')
|
|
243
256
|
.option(' --joinfk')
|
|
244
|
-
.option(' --skip-db-constraints')
|
|
245
257
|
.option('-d, --dialect <dialect>', ['hana', 'sqlite', 'plain'])
|
|
246
258
|
.option('-u, --user <user>')
|
|
247
259
|
.option('-l, --locale <locale>')
|
|
@@ -267,7 +279,6 @@ optionProcessor.command('Q, toSql')
|
|
|
267
279
|
combination with "hana" dialect.
|
|
268
280
|
--render-virtual Render virtual elements in views and draft tables
|
|
269
281
|
--joinfk Create JOINs for foreign key accesses
|
|
270
|
-
--skip-db-constraints Do not render referential constraints for associations
|
|
271
282
|
-d, --dialect <dialect> SQL dialect to be generated:
|
|
272
283
|
plain : (default) Common SQL - no assumptions about DB restrictions
|
|
273
284
|
hana : SQL with HANA specific language features
|
|
@@ -315,7 +326,7 @@ optionProcessor.command('manageConstraints')
|
|
|
315
326
|
|
|
316
327
|
(internal, subject to change): Generate SQL DDL ALTER TABLE statements to add / modify
|
|
317
328
|
referential constraints on an existing model.
|
|
318
|
-
Combine with options "--
|
|
329
|
+
Combine with options "--integrity-not-enforced" and "--integrity-not-validated"
|
|
319
330
|
to switch off foreign key constraint enforcement / validation.
|
|
320
331
|
|
|
321
332
|
Options
|
|
@@ -363,6 +374,7 @@ optionProcessor.command('toCsn')
|
|
|
363
374
|
|
|
364
375
|
optionProcessor.command('parseCdl')
|
|
365
376
|
.option('-h, --help')
|
|
377
|
+
.positionalArgument('<file>')
|
|
366
378
|
.help(`
|
|
367
379
|
Usage: cdsc parseCdl [options] <file>
|
|
368
380
|
|
|
@@ -375,14 +387,17 @@ optionProcessor.command('parseCdl')
|
|
|
375
387
|
|
|
376
388
|
optionProcessor.command('explain')
|
|
377
389
|
.option('-h, --help')
|
|
390
|
+
.positionalArgument('<message-id>')
|
|
378
391
|
.help(`
|
|
379
392
|
Usage: cdsc explain [options] <message-id>
|
|
380
393
|
|
|
381
394
|
Explain the compiler message that has the given message-id.
|
|
382
395
|
The explanation contains a faulty example and a solution.
|
|
383
396
|
|
|
397
|
+
Use \`explain list\` to list all available messages.
|
|
398
|
+
|
|
384
399
|
Options
|
|
385
|
-
-h, --help
|
|
400
|
+
-h, --help Show this help text
|
|
386
401
|
`);
|
|
387
402
|
|
|
388
403
|
module.exports = {
|
|
@@ -44,7 +44,7 @@ class DuplicateChecker {
|
|
|
44
44
|
* Add an artifact to the "seen"-list
|
|
45
45
|
*
|
|
46
46
|
* @param {string} name Persistence name of the artifact
|
|
47
|
-
* @param {CSN.Location} location CSN location of the artifact
|
|
47
|
+
* @param {CSN.Location|CSN.Path} location CSN location of the artifact
|
|
48
48
|
* @param {string} modelName CSN artifact name
|
|
49
49
|
*/
|
|
50
50
|
addArtifact( name, location, modelName ) {
|
package/lib/render/toCdl.js
CHANGED
|
@@ -10,7 +10,7 @@ const {
|
|
|
10
10
|
const keywords = require('../base/keywords');
|
|
11
11
|
const { renderFunc, beautifyExprArray, findElement } = require('./utils/common');
|
|
12
12
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
13
|
-
const timetrace = require('../utils/timetrace');
|
|
13
|
+
const { timetrace } = require('../utils/timetrace');
|
|
14
14
|
const { csnRefs } = require('../model/csnRefs');
|
|
15
15
|
const { forEachDefinition } = require('../model/csnUtils');
|
|
16
16
|
const enrichUniversalCsn = require('../transform/universalCsnEnricher');
|
|
@@ -579,7 +579,7 @@ function toCdsSourceCsn(csn, options) {
|
|
|
579
579
|
* @return {string}
|
|
580
580
|
*/
|
|
581
581
|
function renderQueryActionsAndFunctions(artifactName, art, env) {
|
|
582
|
-
let result =
|
|
582
|
+
let result = renderActionsAndFunctions(art, env);
|
|
583
583
|
// Even if we have seen actions/functions, they might all have been ignored
|
|
584
584
|
if (result !== '')
|
|
585
585
|
result = `${env.indent}extend entity ${artifactName} with${result};`;
|
|
@@ -612,7 +612,7 @@ function toCdsSourceCsn(csn, options) {
|
|
|
612
612
|
}
|
|
613
613
|
// Now iterate elements - render an annotation if it is different from the column's
|
|
614
614
|
const childEnv = increaseIndent(env);
|
|
615
|
-
let result =
|
|
615
|
+
let result = '';
|
|
616
616
|
for (const elemName in art.elements) {
|
|
617
617
|
let elemAnnotations = '';
|
|
618
618
|
const elem = art.elements[elemName];
|
|
@@ -715,7 +715,7 @@ function toCdsSourceCsn(csn, options) {
|
|
|
715
715
|
|
|
716
716
|
// Even the first step might have parameters and/or a filter
|
|
717
717
|
if (path.ref[0].args)
|
|
718
|
-
result += `(${renderArgs(path.ref[0]
|
|
718
|
+
result += `(${renderArgs(path.ref[0], ':', env)})`;
|
|
719
719
|
|
|
720
720
|
if (path.ref[0].where)
|
|
721
721
|
result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env, true, true)}]`;
|
|
@@ -1404,6 +1404,12 @@ function toCdsSourceCsn(csn, options) {
|
|
|
1404
1404
|
// FIXME: no extra magic with x.param or x.global
|
|
1405
1405
|
return `${(x.param || x.global) ? ':' : ''}${x.ref.map(renderPathStep).join('.')}`;
|
|
1406
1406
|
}
|
|
1407
|
+
else if (x.xpr && x.func) {
|
|
1408
|
+
// window function
|
|
1409
|
+
const funcDef = renderFunc( x.func, x, null, a => renderArgs(a, '=>', env) );
|
|
1410
|
+
const windowFunctionOperator = x.xpr.shift(); // OVER ...
|
|
1411
|
+
return `${funcDef} ${windowFunctionOperator} ( ${renderExpr(x.xpr, env, true)} )`;
|
|
1412
|
+
}
|
|
1407
1413
|
// Function call, possibly with args (use '=>' for named args)
|
|
1408
1414
|
else if (x.func) {
|
|
1409
1415
|
// test for non-regular HANA identifier that needs to be quoted
|
|
@@ -1474,13 +1480,13 @@ function toCdsSourceCsn(csn, options) {
|
|
|
1474
1480
|
|
|
1475
1481
|
// Not really a path step but an object-like function call
|
|
1476
1482
|
if (s.func)
|
|
1477
|
-
return `${s.func}(${renderArgs(s
|
|
1483
|
+
return `${s.func}(${renderArgs(s, '=>', env)})`;
|
|
1478
1484
|
|
|
1479
1485
|
// Path step, possibly with view parameters and/or filters
|
|
1480
1486
|
let result = `${quoteOrUppercaseId(s.id)}`;
|
|
1481
1487
|
if (s.args) {
|
|
1482
1488
|
// View parameters
|
|
1483
|
-
result += `(${renderArgs(s
|
|
1489
|
+
result += `(${renderArgs(s, ':', env)})`;
|
|
1484
1490
|
}
|
|
1485
1491
|
if (s.where) {
|
|
1486
1492
|
// Filter, possibly with cardinality
|
|
@@ -1498,12 +1504,13 @@ function toCdsSourceCsn(csn, options) {
|
|
|
1498
1504
|
* Render function arguments or view parameters (positional if array, named if object/dict),
|
|
1499
1505
|
* using 'sep' as separator for positional parameters
|
|
1500
1506
|
*
|
|
1501
|
-
* @param {object
|
|
1507
|
+
* @param {object} node with `args` to render
|
|
1502
1508
|
* @param {string} sep
|
|
1503
1509
|
* @param {CdlRenderEnvironment} env
|
|
1504
1510
|
* @returns {string}
|
|
1505
1511
|
*/
|
|
1506
|
-
function renderArgs(
|
|
1512
|
+
function renderArgs(node, sep, env) {
|
|
1513
|
+
const args = node.args ? node.args : {};
|
|
1507
1514
|
// Positional arguments
|
|
1508
1515
|
if (Array.isArray(args))
|
|
1509
1516
|
return args.map(arg => renderExpr(arg, env)).join(', ');
|