@sap/cds-compiler 2.10.4 → 2.11.0
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 +50 -0
- package/bin/cdsc.js +42 -25
- package/bin/cdsse.js +1 -0
- package/doc/CHANGELOG_BETA.md +4 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +9 -23
- package/lib/api/options.js +12 -4
- package/lib/api/validate.js +23 -2
- package/lib/backends.js +9 -8
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/message-registry.js +10 -2
- package/lib/base/messages.js +23 -9
- package/lib/base/model.js +5 -4
- package/lib/base/optionProcessorHelper.js +56 -22
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/unknownMagic.js +6 -3
- package/lib/compiler/assert-consistency.js +7 -0
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +28 -1
- package/lib/compiler/checks.js +2 -1
- package/lib/compiler/definer.js +58 -91
- package/lib/compiler/index.js +16 -4
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +93 -34
- package/lib/compiler/shared.js +29 -202
- package/lib/compiler/utils.js +173 -0
- package/lib/edm/annotations/genericTranslation.js +1 -1
- package/lib/edm/csn2edm.js +3 -2
- package/lib/edm/edmPreprocessor.js +31 -36
- 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 +169 -34
- package/lib/language/antlrParser.js +11 -0
- package/lib/language/genericAntlrParser.js +72 -14
- package/lib/language/language.g4 +73 -0
- package/lib/main.d.ts +136 -17
- package/lib/main.js +3 -1
- package/lib/model/api.js +2 -2
- package/lib/model/csnRefs.js +108 -31
- package/lib/model/csnUtils.js +63 -29
- package/lib/model/enrichCsn.js +36 -9
- package/lib/model/revealInternalProperties.js +20 -4
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +29 -18
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/toCdl.js +9 -3
- package/lib/render/toHdbcds.js +16 -36
- package/lib/render/toSql.js +23 -5
- package/lib/transform/db/constraints.js +278 -119
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +6 -4
- package/lib/transform/db/flattening.js +17 -1
- package/lib/transform/db/transformExists.js +61 -2
- package/lib/transform/db/views.js +438 -0
- package/lib/transform/forHanaNew.js +56 -435
- package/lib/transform/forOdataNew.js +9 -2
- package/lib/transform/localized.js +2 -0
- package/lib/transform/transformUtilsNew.js +10 -0
- package/lib/transform/translateAssocsToJoins.js +5 -13
- package/lib/utils/file.js +5 -3
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
package/lib/model/csnUtils.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { setProp } = require('../base/model');
|
|
4
4
|
const { csnRefs } = require('../model/csnRefs');
|
|
5
|
+
const { isBuiltinType } = require('../compiler/builtins.js')
|
|
5
6
|
const { sortCsn, cloneCsnDictionary: _cloneCsnDictionary } = require('../json/to-csn');
|
|
6
7
|
const version = require('../../package.json').version;
|
|
7
8
|
|
|
@@ -11,8 +12,8 @@ const version = require('../../package.json').version;
|
|
|
11
12
|
* Generic Callback
|
|
12
13
|
*
|
|
13
14
|
* @callback genericCallback
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
15
|
+
* @param {any} art
|
|
16
|
+
* @param {string} name Artifact Name
|
|
16
17
|
* @param {string} prop Dictionary Property
|
|
17
18
|
* @param {CSN.Path} path Location
|
|
18
19
|
* @param {CSN.Artifact} [dictionary]
|
|
@@ -457,8 +458,8 @@ function getUtils(model) {
|
|
|
457
458
|
return resultNode;
|
|
458
459
|
}
|
|
459
460
|
}
|
|
460
|
-
|
|
461
|
-
|
|
461
|
+
|
|
462
|
+
|
|
462
463
|
/**
|
|
463
464
|
* Resolve to the final type of a type, that means follow type chains, references to other types or
|
|
464
465
|
* elements a.s.o
|
|
@@ -497,12 +498,12 @@ function getUtils(model) {
|
|
|
497
498
|
* Composed types (structures, entities, views, ...) are returned as type objects, if not drilled down into
|
|
498
499
|
* the elements. Path steps that have no corresponding element lead to 'undefined'. Refs to something that has
|
|
499
500
|
* no type (e.g. expr in a view without explicit type) returns 'null'
|
|
500
|
-
*
|
|
501
|
+
*
|
|
501
502
|
* @param {string|object} type Type - either string or ref
|
|
502
|
-
* @param {CSN.Path} path
|
|
503
|
+
* @param {CSN.Path} path
|
|
503
504
|
* @param {WeakMap} [resolved=new WeakMap()] WeakMap containing already resolved refs - if a ref is not cached, it will be resolved JIT
|
|
504
|
-
* @param {object} [cycleCheck] Dictionary to remember already resolved types - to be cycle-safe
|
|
505
|
-
* @returns
|
|
505
|
+
* @param {object} [cycleCheck] Dictionary to remember already resolved types - to be cycle-safe
|
|
506
|
+
* @returns
|
|
506
507
|
*/
|
|
507
508
|
function getFinalBaseType(type, path = [], resolved = new WeakMap(), cycleCheck = undefined) {
|
|
508
509
|
if (!type)
|
|
@@ -552,16 +553,6 @@ function getUtils(model) {
|
|
|
552
553
|
}
|
|
553
554
|
}
|
|
554
555
|
|
|
555
|
-
// Tell if a type is (directly) a builtin type
|
|
556
|
-
// Note that in CSN builtins are not in the definition of the model, so we can only check against their absolute names.
|
|
557
|
-
// Builtin types are "cds.<something>", i.e. they are directly in 'cds', but not for example
|
|
558
|
-
// in 'cds.foundation'. Also note, that a type might be a ref object, that refers to something else,
|
|
559
|
-
// so if you consider type chains don't forget first to resolve to the final type before
|
|
560
|
-
function isBuiltinType(type) {
|
|
561
|
-
return typeof(type) === 'string' && type.startsWith('cds.') && !type.startsWith('cds.foundation.')
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
556
|
/**
|
|
566
557
|
* Deeply clone the given CSN model and return it.
|
|
567
558
|
* In testMode (or with testSortCsn), definitions are sorted.
|
|
@@ -817,11 +808,25 @@ function forAllQueries(query, callback, path = []){
|
|
|
817
808
|
}
|
|
818
809
|
}
|
|
819
810
|
|
|
820
|
-
function forAllElements(artifact, artifactName, cb){
|
|
811
|
+
function forAllElements(artifact, artifactName, cb, includeActions = false){
|
|
821
812
|
if(artifact.elements) {
|
|
822
813
|
cb(artifact, artifact.elements, ['definitions', artifactName, 'elements']);
|
|
823
814
|
}
|
|
824
815
|
|
|
816
|
+
if(includeActions && artifact.actions) {
|
|
817
|
+
Object.entries(artifact.actions).forEach( ([actionName, action]) => {
|
|
818
|
+
const path = ['definitions', artifactName, 'actions', actionName];
|
|
819
|
+
if(action.params) {
|
|
820
|
+
Object.entries(action.params).forEach( ([paramName, param]) => {
|
|
821
|
+
if(param.elements)
|
|
822
|
+
cb(param, param.elements, path.concat(['params', paramName, 'elements']));
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
if(action.returns && action.returns.elements)
|
|
826
|
+
cb(action.returns, action.returns.elements,path.concat(['returns', 'elements']));
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
|
|
825
830
|
if(artifact.query) {
|
|
826
831
|
forAllQueries(artifact.query, (q, p) => {
|
|
827
832
|
const s = q.SELECT;
|
|
@@ -871,7 +876,7 @@ function hasAnnotationValue(artifact, annotationName, expected = true) {
|
|
|
871
876
|
* function accepts EDM internal and external options
|
|
872
877
|
*
|
|
873
878
|
* @param {CSN.Element} elementCsn
|
|
874
|
-
* @param {
|
|
879
|
+
* @param {ODataOptions} options EDM specific options
|
|
875
880
|
*/
|
|
876
881
|
function isEdmPropertyRendered(elementCsn, options) {
|
|
877
882
|
if(options.toOdata)
|
|
@@ -921,10 +926,10 @@ function getArtifactDatabaseNameOf(artifactName, namingConvention, csn) {
|
|
|
921
926
|
throw new Error('Unknown naming convention: ' + namingConvention);
|
|
922
927
|
}
|
|
923
928
|
else {
|
|
924
|
-
const namespace = csn;
|
|
925
929
|
console.error(`This invocation of "getArtifactCdsPersistenceName" is deprecated, as it doesn't produce correct output with definition names containing dots - please provide a CSN as the third parameter.`);
|
|
926
930
|
if (namingConvention === 'hdbcds') {
|
|
927
|
-
if (
|
|
931
|
+
if (csn) {
|
|
932
|
+
const namespace = String(csn);
|
|
928
933
|
return `${namespace}::${artifactName.substring(namespace.length + 1)}`;
|
|
929
934
|
}
|
|
930
935
|
return artifactName;
|
|
@@ -1532,7 +1537,7 @@ function sortCsnDefinitionsForTests(csn, options) {
|
|
|
1532
1537
|
if (!options.testMode)
|
|
1533
1538
|
return;
|
|
1534
1539
|
const sorted = Object.create(null);
|
|
1535
|
-
Object.keys(csn.definitions).sort().forEach((name) => {
|
|
1540
|
+
Object.keys(csn.definitions || {}).sort().forEach((name) => {
|
|
1536
1541
|
sorted[name] = csn.definitions[name];
|
|
1537
1542
|
});
|
|
1538
1543
|
csn.definitions = sorted;
|
|
@@ -1542,7 +1547,7 @@ function sortCsnDefinitionsForTests(csn, options) {
|
|
|
1542
1547
|
* Return an array of non-abstract service names contained in CSN
|
|
1543
1548
|
*
|
|
1544
1549
|
* @param {CSN.Model} csn
|
|
1545
|
-
* @returns {
|
|
1550
|
+
* @returns {string[]}
|
|
1546
1551
|
*/
|
|
1547
1552
|
function getServiceNames(csn) {
|
|
1548
1553
|
let result = [];
|
|
@@ -1556,8 +1561,8 @@ function getServiceNames(csn) {
|
|
|
1556
1561
|
|
|
1557
1562
|
/**
|
|
1558
1563
|
* Check wether the artifact is @cds.persistence.skip
|
|
1559
|
-
*
|
|
1560
|
-
* @param {CSN.Artifact} artifact
|
|
1564
|
+
*
|
|
1565
|
+
* @param {CSN.Artifact} artifact
|
|
1561
1566
|
* @returns {Boolean}
|
|
1562
1567
|
*/
|
|
1563
1568
|
function isSkipped(artifact) {
|
|
@@ -1566,9 +1571,9 @@ function isSkipped(artifact) {
|
|
|
1566
1571
|
|
|
1567
1572
|
/**
|
|
1568
1573
|
* Walk path in the CSN and return the result.
|
|
1569
|
-
*
|
|
1570
|
-
* @param {CSN.Model} csn
|
|
1571
|
-
* @param {CSN.Path} path
|
|
1574
|
+
*
|
|
1575
|
+
* @param {CSN.Model} csn
|
|
1576
|
+
* @param {CSN.Path} path
|
|
1572
1577
|
* @returns {object} Whatever is at the end of path
|
|
1573
1578
|
*/
|
|
1574
1579
|
function walkCsnPath(csn, path) {
|
|
@@ -1581,6 +1586,34 @@ function walkCsnPath(csn, path) {
|
|
|
1581
1586
|
return obj;
|
|
1582
1587
|
}
|
|
1583
1588
|
|
|
1589
|
+
/**
|
|
1590
|
+
* If provided, get the replacement string for the given magic variable ref.
|
|
1591
|
+
* No validation is done that the ref is actually magic!
|
|
1592
|
+
*
|
|
1593
|
+
* @param {array} ref
|
|
1594
|
+
* @param {CSN.Options} options
|
|
1595
|
+
* @returns {string|null}
|
|
1596
|
+
*/
|
|
1597
|
+
function getVariableReplacement(ref, options) {
|
|
1598
|
+
if(options && options.variableReplacements) {
|
|
1599
|
+
let replacement = options.variableReplacements;
|
|
1600
|
+
for(let i = 0; i < ref.length; i++) {
|
|
1601
|
+
replacement = replacement[ref[i]];
|
|
1602
|
+
if(replacement === undefined)
|
|
1603
|
+
return null;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if(replacement === undefined)
|
|
1607
|
+
return null; // no valid replacement found
|
|
1608
|
+
else if(typeof replacement === 'string')
|
|
1609
|
+
return replacement; // valid replacement
|
|
1610
|
+
else
|
|
1611
|
+
return null; // $user.foo, but we only have configured $user.foo.bar -> error
|
|
1612
|
+
} else {
|
|
1613
|
+
return null;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1584
1617
|
module.exports = {
|
|
1585
1618
|
getUtils,
|
|
1586
1619
|
cloneCsn,
|
|
@@ -1621,4 +1654,5 @@ module.exports = {
|
|
|
1621
1654
|
getServiceNames,
|
|
1622
1655
|
isSkipped,
|
|
1623
1656
|
walkCsnPath,
|
|
1657
|
+
getVariableReplacement
|
|
1624
1658
|
};
|
package/lib/model/enrichCsn.js
CHANGED
|
@@ -39,6 +39,8 @@ function enrichCsn( csn, options = {} ) {
|
|
|
39
39
|
params: dictionary,
|
|
40
40
|
enum: dictionary,
|
|
41
41
|
mixin: dictionary,
|
|
42
|
+
returns: definition,
|
|
43
|
+
items: definition,
|
|
42
44
|
ref: pathRef,
|
|
43
45
|
type: simpleRef,
|
|
44
46
|
targetAspect: simpleRef,
|
|
@@ -81,10 +83,19 @@ function enrichCsn( csn, options = {} ) {
|
|
|
81
83
|
csnPath.pop();
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
function definition( parent, prop, obj ) {
|
|
87
|
+
const origin = getOrigin( obj ); // before standard for implicit protos inside
|
|
88
|
+
standard( parent, prop, obj );
|
|
89
|
+
if (obj.$origin === undefined && origin != null)
|
|
90
|
+
obj._origin = refLocation( origin );
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
function dictionary( parent, prop, dict ) {
|
|
94
|
+
if (!dict) // value null for inheritance interruption
|
|
95
|
+
return;
|
|
85
96
|
csnPath.push( prop );
|
|
86
97
|
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
87
|
-
|
|
98
|
+
definition( dict, name, dict[name] );
|
|
88
99
|
}
|
|
89
100
|
if (!Object.prototype.propertyIsEnumerable.call( parent, prop ))
|
|
90
101
|
parent['$'+prop] = dict;
|
|
@@ -123,13 +134,17 @@ function enrichCsn( csn, options = {} ) {
|
|
|
123
134
|
|
|
124
135
|
function $origin( parent, prop, ref ) {
|
|
125
136
|
if (options.testMode) {
|
|
126
|
-
if (Array.isArray( ref ))
|
|
127
|
-
parent._origin = refLocation( getOrigin( parent ) );
|
|
137
|
+
if (Array.isArray( ref ) || typeof ref === 'string') // $origin: […], not $origin: {…}
|
|
138
|
+
parent._origin = refLocation( getOrigin( parent, true ) );
|
|
139
|
+
else if ( ref )
|
|
140
|
+
standard( parent, prop, ref )
|
|
128
141
|
}
|
|
129
142
|
else {
|
|
130
143
|
try {
|
|
131
|
-
if (Array.isArray( ref )) // $origin: […], not $origin: {…}
|
|
132
|
-
parent._origin = refLocation( getOrigin( parent ) );
|
|
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 )
|
|
133
148
|
} catch (e) {
|
|
134
149
|
parent._origin = e.toString();
|
|
135
150
|
}
|
|
@@ -171,10 +186,10 @@ function enrichCsn( csn, options = {} ) {
|
|
|
171
186
|
csnPath.pop();
|
|
172
187
|
}
|
|
173
188
|
|
|
174
|
-
function _cache_debug( obj ) {
|
|
189
|
+
function _cache_debug( obj, subCache ) {
|
|
175
190
|
if (options.enrichCsn !== 'DEBUG')
|
|
176
191
|
return;
|
|
177
|
-
const cache = __getCache_forEnrichCsnDebugging( obj );
|
|
192
|
+
const cache = subCache || __getCache_forEnrichCsnDebugging( obj );
|
|
178
193
|
if (!cache)
|
|
179
194
|
return;
|
|
180
195
|
if (cache.$$objectNumber > 0) {
|
|
@@ -197,8 +212,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
197
212
|
}
|
|
198
213
|
else if (name[0] !== '$' || !Object.getPrototypeOf( val )) {
|
|
199
214
|
// ‹name›: dictionary of CSN nodes,
|
|
200
|
-
// ‹$name›: dictionary of cache values if no prototype
|
|
201
|
-
|
|
215
|
+
// ‹$name›: dictionary of cache values if no prototype
|
|
216
|
+
if (name !== '$aliases') {
|
|
217
|
+
obj.$$cacheObject[name] = Object.keys( val ); // TODO: or dict?
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const sub = Object.create(null);
|
|
221
|
+
for (const n in val) {
|
|
222
|
+
const alias = val[n];
|
|
223
|
+
const c = {};
|
|
224
|
+
_cache_debug( c, alias );
|
|
225
|
+
sub[n] = c.$$cacheObject;
|
|
226
|
+
}
|
|
227
|
+
obj.$$cacheObject[name] = sub;
|
|
228
|
+
}
|
|
202
229
|
}
|
|
203
230
|
else if (Array.isArray( val )) {
|
|
204
231
|
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 ) {
|
|
@@ -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,10 @@ 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' ])
|
|
32
34
|
.option(' --deprecated <list>')
|
|
33
35
|
.option(' --hana-flavor')
|
|
34
36
|
.option(' --direct-backend')
|
|
@@ -39,7 +41,8 @@ optionProcessor
|
|
|
39
41
|
.option(' --doc-comment')
|
|
40
42
|
.option(' --add-texts-language-assoc')
|
|
41
43
|
.option(' --localized-without-coalesce')
|
|
42
|
-
.option(' --
|
|
44
|
+
.option(' --default-binary-length <length>')
|
|
45
|
+
.option(' --default-string-length <length>')
|
|
43
46
|
.option(' --no-recompile')
|
|
44
47
|
.positionalArgument('<files...>')
|
|
45
48
|
.help(`
|
|
@@ -75,7 +78,8 @@ optionProcessor
|
|
|
75
78
|
-- Indicate the end of options (helpful if source names start with "-")
|
|
76
79
|
|
|
77
80
|
Type options
|
|
78
|
-
--
|
|
81
|
+
--default-binary-length <length> Default 'length' for 'cds.Binary'
|
|
82
|
+
--default-string-length <length> Default 'length' for 'cds.String'
|
|
79
83
|
|
|
80
84
|
Diagnostic options
|
|
81
85
|
--trace-parser Trace parser
|
|
@@ -90,16 +94,23 @@ optionProcessor
|
|
|
90
94
|
--beta-mode Enable all unsupported, incomplete (beta) features
|
|
91
95
|
--beta <list> Comma separated list of unsupported, incomplete (beta) features to use.
|
|
92
96
|
Valid values are:
|
|
93
|
-
foreignKeyConstraints
|
|
94
97
|
addTextsLanguageAssoc
|
|
95
98
|
hanaAssocRealCardinality
|
|
96
99
|
mapAssocToJoinCardinality
|
|
97
100
|
ignoreAssocPublishingInUnion
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
--integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
|
|
102
|
+
This option is also applied to result of "cdsc manageConstraints"
|
|
103
|
+
--integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
|
|
104
|
+
This option is also applied to result of "cdsc manageConstraints"
|
|
105
|
+
--assert-integrity <mode> Turn DB constraints on/off:
|
|
106
|
+
true : Constraints will be generated for all associations if
|
|
107
|
+
the assert-integrity-type is set to DB
|
|
108
|
+
false : No constraints will be generated
|
|
109
|
+
individual : Constraints will be generated for selected associations
|
|
110
|
+
--assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
|
|
111
|
+
RT : (default) No database constraint for an association
|
|
112
|
+
if not explicitly demanded via annotation
|
|
113
|
+
DB : Create database constraints for associations
|
|
103
114
|
--deprecated <list> Comma separated list of deprecated options.
|
|
104
115
|
Valid values are:
|
|
105
116
|
noElementsExpansion
|
|
@@ -130,7 +141,7 @@ optionProcessor
|
|
|
130
141
|
to "sap.common.Languages" if it exists
|
|
131
142
|
--localized-without-coalesce Omit coalesce in localized convenience views
|
|
132
143
|
--no-recompile Don't recompile in case of internal errors
|
|
133
|
-
|
|
144
|
+
|
|
134
145
|
Commands
|
|
135
146
|
H, toHana [options] <files...> Generate HANA CDS source files
|
|
136
147
|
O, toOdata [options] <files...> Generate ODATA metadata and annotations
|
|
@@ -140,7 +151,7 @@ optionProcessor
|
|
|
140
151
|
parseCdl [options] <file> Generate a CSN that is close to the CDL source.
|
|
141
152
|
explain <message-id> Explain a compiler message.
|
|
142
153
|
toRename [options] <files...> (internal) Generate SQL DDL rename statements
|
|
143
|
-
manageConstraints [options] <files...>
|
|
154
|
+
manageConstraints [options] <files...> (internal) Generate ALTER TABLE statements to
|
|
144
155
|
add / modify referential constraints.
|
|
145
156
|
`);
|
|
146
157
|
|
|
@@ -150,7 +161,6 @@ optionProcessor.command('H, toHana')
|
|
|
150
161
|
.option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
|
|
151
162
|
.option(' --render-virtual')
|
|
152
163
|
.option(' --joinfk')
|
|
153
|
-
.option(' --skip-db-constraints')
|
|
154
164
|
.option('-u, --user <user>')
|
|
155
165
|
.option('-s, --src')
|
|
156
166
|
.option('-c, --csn')
|
|
@@ -174,7 +184,6 @@ optionProcessor.command('H, toHana')
|
|
|
174
184
|
using element names with dots).
|
|
175
185
|
--render-virtual Render virtual elements in views and draft tables
|
|
176
186
|
--joinfk Create JOINs for foreign key accesses
|
|
177
|
-
--skip-db-constraints Do not render referential constraints for associations
|
|
178
187
|
-u, --user <user> Value for the "$user" variable
|
|
179
188
|
-s, --src (default) Generate HANA CDS source files "<artifact>.hdbcds"
|
|
180
189
|
-c, --csn Generate "hana_csn.json" with HANA-preprocessed model
|
|
@@ -241,7 +250,6 @@ optionProcessor.command('Q, toSql')
|
|
|
241
250
|
.option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
|
|
242
251
|
.option(' --render-virtual')
|
|
243
252
|
.option(' --joinfk')
|
|
244
|
-
.option(' --skip-db-constraints')
|
|
245
253
|
.option('-d, --dialect <dialect>', ['hana', 'sqlite', 'plain'])
|
|
246
254
|
.option('-u, --user <user>')
|
|
247
255
|
.option('-l, --locale <locale>')
|
|
@@ -267,7 +275,6 @@ optionProcessor.command('Q, toSql')
|
|
|
267
275
|
combination with "hana" dialect.
|
|
268
276
|
--render-virtual Render virtual elements in views and draft tables
|
|
269
277
|
--joinfk Create JOINs for foreign key accesses
|
|
270
|
-
--skip-db-constraints Do not render referential constraints for associations
|
|
271
278
|
-d, --dialect <dialect> SQL dialect to be generated:
|
|
272
279
|
plain : (default) Common SQL - no assumptions about DB restrictions
|
|
273
280
|
hana : SQL with HANA specific language features
|
|
@@ -315,7 +322,7 @@ optionProcessor.command('manageConstraints')
|
|
|
315
322
|
|
|
316
323
|
(internal, subject to change): Generate SQL DDL ALTER TABLE statements to add / modify
|
|
317
324
|
referential constraints on an existing model.
|
|
318
|
-
Combine with options "--
|
|
325
|
+
Combine with options "--integrity-not-enforced" and "--integrity-not-validated"
|
|
319
326
|
to switch off foreign key constraint enforcement / validation.
|
|
320
327
|
|
|
321
328
|
Options
|
|
@@ -363,6 +370,7 @@ optionProcessor.command('toCsn')
|
|
|
363
370
|
|
|
364
371
|
optionProcessor.command('parseCdl')
|
|
365
372
|
.option('-h, --help')
|
|
373
|
+
.positionalArgument('<file>')
|
|
366
374
|
.help(`
|
|
367
375
|
Usage: cdsc parseCdl [options] <file>
|
|
368
376
|
|
|
@@ -375,14 +383,17 @@ optionProcessor.command('parseCdl')
|
|
|
375
383
|
|
|
376
384
|
optionProcessor.command('explain')
|
|
377
385
|
.option('-h, --help')
|
|
386
|
+
.positionalArgument('<message-id>')
|
|
378
387
|
.help(`
|
|
379
388
|
Usage: cdsc explain [options] <message-id>
|
|
380
389
|
|
|
381
390
|
Explain the compiler message that has the given message-id.
|
|
382
391
|
The explanation contains a faulty example and a solution.
|
|
383
392
|
|
|
393
|
+
Use \`explain list\` to list all available messages.
|
|
394
|
+
|
|
384
395
|
Options
|
|
385
|
-
-h, --help
|
|
396
|
+
-h, --help Show this help text
|
|
386
397
|
`);
|
|
387
398
|
|
|
388
399
|
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];
|
|
@@ -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
|