@sap/cds-compiler 2.4.4 → 2.10.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 +241 -1
- package/bin/.eslintrc.json +17 -0
- package/bin/cds_update_identifiers.js +8 -7
- package/bin/cdsc.js +180 -132
- package/bin/cdshi.js +18 -11
- package/bin/cdsse.js +38 -32
- package/bin/cdsv2m.js +8 -7
- package/doc/CHANGELOG_BETA.md +36 -1
- package/lib/api/main.js +81 -100
- package/lib/api/options.js +17 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/location.js +2 -2
- package/lib/base/message-registry.js +66 -4
- package/lib/base/messages.js +84 -27
- package/lib/base/model.js +2 -61
- package/lib/checks/arrayOfs.js +0 -1
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/enricher.js +8 -2
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +27 -9
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +66 -13
- package/lib/compiler/assert-consistency.js +24 -12
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +101 -39
- package/lib/compiler/index.js +88 -59
- package/lib/compiler/resolver.js +455 -209
- package/lib/compiler/shared.js +57 -33
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +128 -99
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -127
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +74 -28
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +18 -4
- package/lib/gen/language.tokens +124 -118
- package/lib/gen/languageLexer.interp +13 -1
- package/lib/gen/languageLexer.js +870 -839
- package/lib/gen/languageLexer.tokens +116 -111
- package/lib/gen/languageParser.js +5894 -5614
- package/lib/json/from-csn.js +152 -67
- package/lib/json/to-csn.js +334 -135
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +24 -14
- package/lib/language/language.g4 +188 -128
- package/lib/main.d.ts +435 -0
- package/lib/main.js +31 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +463 -187
- package/lib/model/csnUtils.js +280 -136
- package/lib/model/enrichCsn.js +75 -4
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +70 -25
- package/lib/optionProcessor.js +13 -10
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +123 -40
- package/lib/render/toHdbcds.js +156 -65
- package/lib/render/toSql.js +87 -11
- package/lib/render/utils/common.js +55 -9
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/{sql → db}/.eslintrc.json +0 -0
- package/lib/transform/{sql → db}/assertUnique.js +7 -8
- package/lib/transform/{sql → db}/constraints.js +35 -20
- package/lib/transform/db/draft.js +353 -0
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
- package/lib/transform/{sql → db}/helpers.js +0 -0
- package/lib/transform/{sql → db}/transformExists.js +256 -60
- package/lib/transform/forHanaNew.js +216 -765
- package/lib/transform/forOdataNew.js +60 -56
- package/lib/transform/localized.js +48 -26
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
- package/lib/transform/odata/generateForeignKeyElements.js +13 -12
- package/lib/transform/odata/referenceFlattener.js +60 -36
- package/lib/transform/odata/sortByAssociationDependency.js +4 -4
- package/lib/transform/odata/structuralPath.js +76 -0
- package/lib/transform/odata/structureFlattener.js +21 -22
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +27 -17
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +141 -77
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/timetrace.js +6 -1
- package/package.json +2 -1
- package/lib/base/deepCopy.js +0 -66
- package/lib/json/walker.js +0 -26
- package/lib/utils/string.js +0 -17
package/bin/cdsse.js
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const commands = {
|
|
18
|
-
complete, find, lint
|
|
19
|
-
}
|
|
18
|
+
complete, find, lint,
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
const fs = require('fs');
|
|
22
22
|
const path = require('path');
|
|
@@ -25,12 +25,12 @@ const main = require('../lib/main');
|
|
|
25
25
|
const { locationString } = require('../lib/base/messages');
|
|
26
26
|
const { availableBetaFlags: beta } = require('../lib/base/model');
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const { argv } = process;
|
|
29
|
+
const cmd = commands[argv[2]];
|
|
30
|
+
const line = Number.parseInt( argv[3] );
|
|
31
|
+
const column = Number.parseInt( argv[4] );
|
|
32
|
+
const file = argv[5];
|
|
33
|
+
const frel = path.relative( '', file || '' );
|
|
34
34
|
// TODO: proper realname
|
|
35
35
|
|
|
36
36
|
if (argv.length > 5 && cmd && line > 0 && column > 0)
|
|
@@ -62,17 +62,19 @@ function complete( err, buf ) {
|
|
|
62
62
|
hasId = tokensAt( buf, off.prefix, off.col, false );
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
|
|
66
|
-
if ([':', '<', '.', '>', '!', '|', '='].includes( charBefore ))
|
|
65
|
+
const charBefore = buf[off.prefix - 1];
|
|
66
|
+
if ([ ':', '<', '.', '>', '!', '|', '=' ].includes( charBefore ))
|
|
67
67
|
// If first of multi-char symbols from 'literalNames' in
|
|
68
68
|
// gen/languageParser, calculate "symbol continuation"
|
|
69
|
-
tokensAt( buf, off.prefix-1, off.col-1, charBefore );
|
|
69
|
+
tokensAt( buf, off.prefix - 1, off.col - 1, charBefore );
|
|
70
70
|
hasId = tokensAt( buf, off.prefix, off.col, true );
|
|
71
71
|
}
|
|
72
72
|
if (hasId) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
compiler.compileX( [file], '', {
|
|
73
|
+
const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
|
|
74
|
+
const fname = path.resolve( '', file );
|
|
75
|
+
compiler.compileX( [ file ], '', {
|
|
76
|
+
attachValidNames: true, lintMode: true, beta, messages: [],
|
|
77
|
+
}, { [fname]: src } )
|
|
76
78
|
.then( ident, ident );
|
|
77
79
|
}
|
|
78
80
|
return true;
|
|
@@ -80,11 +82,11 @@ function complete( err, buf ) {
|
|
|
80
82
|
function ident( xsnOrErr ) {
|
|
81
83
|
if (!(xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages))
|
|
82
84
|
return usage( xsnOrErr );
|
|
83
|
-
|
|
85
|
+
const vn = messageAt( xsnOrErr, 'validNames', off.col ) || Object.create(null);
|
|
84
86
|
// TODO: if there is no such message, use console.log( 'arbitrary identifier' )
|
|
85
87
|
// if we want to avoid that the editor switches to fuzzy completion match
|
|
86
88
|
// against the prefix (not yet done anyway)
|
|
87
|
-
for (
|
|
89
|
+
for (const n in vn)
|
|
88
90
|
console.log( n, vn[n].kind );
|
|
89
91
|
if (!Object.keys( vn ).length)
|
|
90
92
|
console.log( 'unknown_identifier', 'identifier' );
|
|
@@ -104,19 +106,21 @@ function find( err, buf ) {
|
|
|
104
106
|
return usage();
|
|
105
107
|
if (off.prefix === off.cursor) // not at name
|
|
106
108
|
return true;
|
|
107
|
-
const src = buf.substring( 0, off.prefix )
|
|
109
|
+
const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
|
|
108
110
|
const fname = path.resolve( '', file );
|
|
109
|
-
compiler.compileX( [file], '', {
|
|
111
|
+
compiler.compileX( [ file ], '', {
|
|
112
|
+
attachValidNames: true, lintMode: true, beta, messages: [],
|
|
113
|
+
}, { [fname]: src } )
|
|
110
114
|
.then( show, show );
|
|
111
115
|
return true;
|
|
112
116
|
|
|
113
|
-
function show(
|
|
117
|
+
function show( xsnOrErr ) {
|
|
114
118
|
if (!(xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages))
|
|
115
119
|
return usage( xsnOrErr );
|
|
116
|
-
|
|
120
|
+
const vn = messageAt( xsnOrErr, 'validNames', off.col ) || Object.create(null);
|
|
117
121
|
const art = vn[buf.substring( off.prefix, off.cursor )];
|
|
118
122
|
if (art)
|
|
119
|
-
console.log( locationString( art.name.location || art.location )
|
|
123
|
+
console.log( `${locationString( art.name.location || art.location )}: Definition` );
|
|
120
124
|
return true;
|
|
121
125
|
}
|
|
122
126
|
}
|
|
@@ -124,25 +128,25 @@ function find( err, buf ) {
|
|
|
124
128
|
function lint( err, buf ) {
|
|
125
129
|
if (err)
|
|
126
130
|
return usage( err );
|
|
127
|
-
|
|
128
|
-
compiler.compileX( [file], '', { lintMode: true, beta, messages: [] }, { [fname]: buf } )
|
|
131
|
+
const fname = path.resolve( '', file );
|
|
132
|
+
compiler.compileX( [ file ], '', { lintMode: true, beta, messages: [] }, { [fname]: buf } )
|
|
129
133
|
.then( display, display );
|
|
130
134
|
return true;
|
|
131
135
|
|
|
132
136
|
function display( xsnOrErr ) {
|
|
133
|
-
|
|
137
|
+
const messages = xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages;
|
|
134
138
|
if (!messages)
|
|
135
139
|
return usage( xsnOrErr );
|
|
136
|
-
for (
|
|
140
|
+
for (const msg of messages)
|
|
137
141
|
console.log( main.messageString( msg ) );
|
|
138
142
|
return true;
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
function tokensAt( buf, offset, col, symbol ) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
for (
|
|
147
|
+
const src = `${buf.substring( 0, offset )}≠${buf.substring( offset )}`;
|
|
148
|
+
const et = messageAt( compiler.parseX( src, frel, { messages: [] } ), 'expectedTokens', col ) || [];
|
|
149
|
+
for (const n of et) {
|
|
146
150
|
if (typeof symbol === 'string') {
|
|
147
151
|
if (n.length > 3 && n.charAt(0) === "'" && n.charAt(1) === symbol)
|
|
148
152
|
console.log( n.slice( 2, -1 ), 'symbolCont' );
|
|
@@ -154,15 +158,17 @@ function tokensAt( buf, offset, col, symbol ) {
|
|
|
154
158
|
else if (/^[A-Z_]+$/.test( n )) {
|
|
155
159
|
console.log( n.toLowerCase(), 'keyword' );
|
|
156
160
|
}
|
|
157
|
-
else if (n !== 'Identifier')
|
|
161
|
+
else if (n !== 'Identifier') {
|
|
158
162
|
console.log( n, 'unknown' );
|
|
163
|
+
}
|
|
159
164
|
}
|
|
160
165
|
return et.includes( 'Identifier' );
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
function messageAt( model, prop, col ) {
|
|
164
|
-
|
|
165
|
-
m => m[prop] && m.location.line === line && m.location.col === col && m.location.file === frel
|
|
169
|
+
const msg = (model.messages || model.options && model.options.messages).find(
|
|
170
|
+
m => m[prop] && m.location.line === line && m.location.col === col && m.location.file === frel
|
|
171
|
+
);
|
|
166
172
|
return msg && msg[prop];
|
|
167
173
|
}
|
|
168
174
|
|
|
@@ -173,7 +179,7 @@ function messageAt( model, prop, col ) {
|
|
|
173
179
|
*/
|
|
174
180
|
function offset( buf, alsoSuffix ) { // for line and column
|
|
175
181
|
let pos = 0;
|
|
176
|
-
for (let l = line-1; l; --l) {
|
|
182
|
+
for (let l = line - 1; l; --l) {
|
|
177
183
|
pos = buf.indexOf( '\n', pos ) + 1;
|
|
178
184
|
if (!pos)
|
|
179
185
|
return false;
|
package/bin/cdsv2m.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
3
5
|
// Very simple command-line interface to support model migration from compiler
|
|
4
6
|
// v1 to v2. (If our client command processor would have been not as difficult
|
|
5
7
|
// as after #2629, we could have a cdsc commend "migrate...)
|
|
6
8
|
|
|
7
|
-
|
|
8
9
|
const commands = {
|
|
9
|
-
ria
|
|
10
|
-
}
|
|
10
|
+
ria,
|
|
11
|
+
};
|
|
11
12
|
const compiler = require('../lib/compiler');
|
|
12
13
|
|
|
13
|
-
const argv = process
|
|
14
|
-
const cmd = commands[
|
|
14
|
+
const { argv } = process;
|
|
15
|
+
const cmd = commands[argv[2]];
|
|
15
16
|
const files = argv.slice(3);
|
|
16
17
|
const options = { messages: [] };
|
|
17
18
|
|
|
@@ -36,8 +37,8 @@ function ria() {
|
|
|
36
37
|
// regex match on message text not for productive code!
|
|
37
38
|
for (const msgObj of msgs) {
|
|
38
39
|
const matches = msgObj.message.match( /["“][^"”]+["”]/g );
|
|
39
|
-
matches.slice(2).forEach( name => {
|
|
40
|
-
annotates[
|
|
40
|
+
matches.slice(2).forEach( (name) => {
|
|
41
|
+
annotates[name.slice( 1, -1 )] = true;
|
|
41
42
|
} );
|
|
42
43
|
}
|
|
43
44
|
for (const name in annotates)
|
package/doc/CHANGELOG_BETA.md
CHANGED
|
@@ -1,12 +1,48 @@
|
|
|
1
1
|
# ChangeLog of Beta Features for cdx compiler and backends
|
|
2
2
|
|
|
3
3
|
<!-- markdownlint-disable MD024 -->
|
|
4
|
+
<!-- markdownlint-disable MD004 -->
|
|
4
5
|
<!-- (no-duplicate-heading)-->
|
|
5
6
|
|
|
6
7
|
Note: `beta` fixes, changes and features are listed in this ChangeLog just for information.
|
|
7
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
8
9
|
**Don't use `beta` fixes, changes and features in productive mode.**
|
|
9
10
|
|
|
11
|
+
## Version 2.6.0
|
|
12
|
+
|
|
13
|
+
### Removed `pretransformedCSN`
|
|
14
|
+
|
|
15
|
+
### Removed `renderSql`
|
|
16
|
+
|
|
17
|
+
### Removed `keylessManagedAssoc`
|
|
18
|
+
|
|
19
|
+
This is now the default - see CHANGELOG entry for 2.6.0
|
|
20
|
+
|
|
21
|
+
### Fixed `nestedProjections`
|
|
22
|
+
|
|
23
|
+
- to.sql/hdi/hdbcds: now work correctly when nested projections are used
|
|
24
|
+
|
|
25
|
+
### Fixed `foreignKeyConstraints`
|
|
26
|
+
|
|
27
|
+
- Always use the name of the association / backlink compared to
|
|
28
|
+
`$self` as name suffix for a constraint
|
|
29
|
+
- Composition of one always result in:
|
|
30
|
+
+ ON DELETE RESTRICT
|
|
31
|
+
+ ON UPDATE RESTRICT
|
|
32
|
+
- Composition of one w/o backlink will result in a constraint in
|
|
33
|
+
the entity where the composition is defined
|
|
34
|
+
|
|
35
|
+
## Version 2.4.4
|
|
36
|
+
|
|
37
|
+
### Added `nestedProjections`
|
|
38
|
+
|
|
39
|
+
- Support `expand`: columns can look like `assoc_or_struct_or_tabalias { col_expression1, … }`,
|
|
40
|
+
`longer.ref as name { *, … } excluding { … }`, `{ col_expression1 as sub1, … } as name`, etc.
|
|
41
|
+
- Support `inline`: columns can look like `assoc_or_struct_or_tabalias.{ col_expression1, … }`,
|
|
42
|
+
`longer.ref[filter = condition].{ *, … } excluding { … }`, `assoc_or_struct_or_tabalias.*`, etc.
|
|
43
|
+
- _Some checks are missing and will be added! Minor changes might occur._
|
|
44
|
+
- **The SQL backends might not work properly yet if nested projections are used!**
|
|
45
|
+
|
|
10
46
|
## Version 2.4.2
|
|
11
47
|
|
|
12
48
|
### Added `keylessManagedAssoc`
|
|
@@ -19,7 +55,6 @@ The compiler behavior concerning `beta` features can change at any time without
|
|
|
19
55
|
Consequently, these associations are not added to the `WITH ASSOCIATIONS` clause or forwarded to HANA CDS.
|
|
20
56
|
Managed Associations without foreign keys must be enabled with `--beta: keylessManagedAssoc`
|
|
21
57
|
|
|
22
|
-
|
|
23
58
|
## Version 2.4.0
|
|
24
59
|
|
|
25
60
|
### Changed `foreignKeyConstraints`
|
package/lib/api/main.js
CHANGED
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
const prepareOptions = require('./options');
|
|
6
6
|
const backends = require('../backends');
|
|
7
|
-
const { setProp
|
|
7
|
+
const { setProp } = require('../base/model');
|
|
8
8
|
const { emptyLocation } = require('../base/location');
|
|
9
|
-
const { CompilationError, makeMessageFunction
|
|
10
|
-
const {
|
|
9
|
+
const { CompilationError, makeMessageFunction } = require('../base/messages');
|
|
10
|
+
const { recompileX } = require('../compiler/index');
|
|
11
|
+
const { compactModel, sortCsn } = require('../json/to-csn');
|
|
11
12
|
const { transform4odataWithCsn } = require('../transform/forOdataNew.js');
|
|
12
13
|
const { toSqlDdl } = require('../render/toSql');
|
|
13
14
|
const { compareModels } = require('../modelCompare/compare');
|
|
14
15
|
const sortViews = require('../model/sortViews');
|
|
15
16
|
const { getResultingName } = require('../model/csnUtils');
|
|
17
|
+
const timetrace = require('../utils/timetrace');
|
|
18
|
+
const { transformForHanaWithCsn } = require('../transform/forHanaNew');
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -31,10 +34,10 @@ const propertyToCheck = {
|
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
const { cloneCsn } = require('../model/csnUtils');
|
|
37
|
+
const { toHdbcdsSource } = require('../render/toHdbcds');
|
|
34
38
|
|
|
35
39
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
36
40
|
const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
|
|
37
|
-
const relevantSqlOptions = [ 'sqlMapping', 'sqlDialect' ];
|
|
38
41
|
const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
39
42
|
|
|
40
43
|
/**
|
|
@@ -152,6 +155,49 @@ function cdl(csn, externalOptions = {}) {
|
|
|
152
155
|
const { result } = backends.toCdlWithCsn(cloneCsn(csn, internalOptions), internalOptions);
|
|
153
156
|
return result;
|
|
154
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Transform a CSN like to.sql
|
|
160
|
+
*
|
|
161
|
+
* @param {CSN.Model} csn Plain input CSN
|
|
162
|
+
* @param {sqlOptions} [options={}] Options
|
|
163
|
+
* @returns {CSN.Model} CSN transformed like to.sql
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
function forSql(csn, options = {}) {
|
|
167
|
+
const internalOptions = prepareOptions.to.sql(options);
|
|
168
|
+
internalOptions.toSql.csn = true;
|
|
169
|
+
return backends.toSqlWithCsn(csn, internalOptions).csn;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Transform a CSN like to.hdi
|
|
173
|
+
*
|
|
174
|
+
* @param {CSN.Model} csn Plain input CSN
|
|
175
|
+
* @param {hdiOptions} [options={}] Options
|
|
176
|
+
* @returns {CSN.Model} CSN transformed like to.hdi
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
function forHdi(csn, options = {}) {
|
|
180
|
+
const internalOptions = prepareOptions.to.hdi(options);
|
|
181
|
+
internalOptions.toSql.csn = true;
|
|
182
|
+
return backends.toSqlWithCsn(csn, internalOptions).csn;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Transform a CSN like to.hdbcds
|
|
186
|
+
*
|
|
187
|
+
* @param {CSN.Model} csn Plain input CSN
|
|
188
|
+
* @param {hdbcdsOptions} [options={}] Options
|
|
189
|
+
* @returns {CSN.Model} CSN transformed like to.hdbcds
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
192
|
+
function forHdbcds(csn, options = {}) {
|
|
193
|
+
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
194
|
+
internalOptions.transformation = 'hdbcds';
|
|
195
|
+
|
|
196
|
+
const hanaCsn = transformForHanaWithCsn(csn, internalOptions, 'to.hdbcds');
|
|
197
|
+
|
|
198
|
+
return internalOptions.testMode ? sortCsn(hanaCsn, internalOptions) : hanaCsn;
|
|
199
|
+
}
|
|
200
|
+
|
|
155
201
|
/**
|
|
156
202
|
* Process the given CSN into SQL.
|
|
157
203
|
*
|
|
@@ -165,18 +211,7 @@ function sql(csn, options = {}) {
|
|
|
165
211
|
// we need the CSN for view sorting
|
|
166
212
|
internalOptions.toSql.csn = true;
|
|
167
213
|
|
|
168
|
-
|
|
169
|
-
if (isBetaEnabled(internalOptions, 'pretransformedCSN') && isPreTransformed(csn, 'sql')) {
|
|
170
|
-
internalOptions.noRecompile = true; // pre-transformed cannot be recompiled!
|
|
171
|
-
checkPreTransformedCsn(csn, internalOptions, relevantSqlOptions, warnAboutMismatchOdata, 'to.sql');
|
|
172
|
-
|
|
173
|
-
intermediateResult = backends.renderSqlWithCsn(csn, internalOptions);
|
|
174
|
-
// attach CSN for view sorting
|
|
175
|
-
intermediateResult.csn = cloneCsn(csn, internalOptions);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
intermediateResult = backends.toSqlWithCsn(csn, internalOptions);
|
|
179
|
-
}
|
|
214
|
+
const intermediateResult = backends.toSqlWithCsn(csn, internalOptions);
|
|
180
215
|
|
|
181
216
|
const result = sortViews(intermediateResult);
|
|
182
217
|
|
|
@@ -338,7 +373,7 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
338
373
|
const afterImage = backends.toSqlWithCsn(csn, internalOptions).csn;
|
|
339
374
|
|
|
340
375
|
// Compare both images.
|
|
341
|
-
const diff = compareModels(beforeImage || afterImage, afterImage);
|
|
376
|
+
const diff = compareModels(beforeImage || afterImage, afterImage, internalOptions);
|
|
342
377
|
|
|
343
378
|
// Convert the diff to SQL.
|
|
344
379
|
internalOptions.forHana = true; // Make it pass the SQL rendering
|
|
@@ -405,10 +440,15 @@ hdi.migration = hdiMigration;
|
|
|
405
440
|
* @returns {HDBCDS} { <filename>:<content>, ...}
|
|
406
441
|
*/
|
|
407
442
|
function hdbcds(csn, options = {}) {
|
|
443
|
+
timetrace.start('to.hdbcds');
|
|
408
444
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
409
|
-
|
|
445
|
+
internalOptions.transformation = 'hdbcds';
|
|
410
446
|
|
|
411
|
-
|
|
447
|
+
const hanaCsn = forHdbcds(csn, internalOptions);
|
|
448
|
+
|
|
449
|
+
const result = flattenResultStructure(toHdbcdsSource(hanaCsn, internalOptions));
|
|
450
|
+
timetrace.stop();
|
|
451
|
+
return result;
|
|
412
452
|
}
|
|
413
453
|
/**
|
|
414
454
|
* Generate a edm document for the given service
|
|
@@ -454,19 +494,17 @@ function edmall(csn, options = {}) {
|
|
|
454
494
|
if (internalOptions.version === 'v2')
|
|
455
495
|
error(null, null, 'OData JSON output is not available for OData V2');
|
|
456
496
|
|
|
457
|
-
let servicesAll;
|
|
458
|
-
|
|
459
497
|
const result = {};
|
|
498
|
+
let oDataCsn = csn;
|
|
460
499
|
|
|
461
|
-
if (isPreTransformed(csn, 'odata'))
|
|
500
|
+
if (isPreTransformed(csn, 'odata'))
|
|
462
501
|
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions, warnAboutMismatchOdata, 'for.odata');
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const services = servicesAll.edmj;
|
|
502
|
+
|
|
503
|
+
else
|
|
504
|
+
oDataCsn = odataInternal(csn, internalOptions);
|
|
505
|
+
|
|
506
|
+
const servicesJson = backends.preparedCsnToEdmAll(oDataCsn, internalOptions);
|
|
507
|
+
const services = servicesJson.edmj;
|
|
470
508
|
for (const serviceName in services) {
|
|
471
509
|
const lEdm = services[serviceName];
|
|
472
510
|
// FIXME: Why only metadata_json - isn't this rather a 'combined_json' ? If so, rename it!
|
|
@@ -555,41 +593,6 @@ function flattenResultStructure(toProcess) {
|
|
|
555
593
|
return result;
|
|
556
594
|
}
|
|
557
595
|
|
|
558
|
-
/**
|
|
559
|
-
* Compute the .hdbcds files that would have been generated by the csn for an undeploy.json.
|
|
560
|
-
* This is needed for the handover between hdbcds and hdbtable - the existing hdbcds artifacts need to be undeployed.
|
|
561
|
-
*
|
|
562
|
-
* @param {any} csn A clean input CSN
|
|
563
|
-
* @param {hdbcdsOptions} [options={}] Options
|
|
564
|
-
* @returns {string[]} Array of .hdbcds filenames
|
|
565
|
-
*/
|
|
566
|
-
function undeploy(csn, options) {
|
|
567
|
-
const hdbcdsResult = hdbcds(csn, options);
|
|
568
|
-
|
|
569
|
-
return Object.keys(hdbcdsResult);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* This function simply renders the given CSN to SQL - no integrity checks, no transformations, no guarantees for correctness.
|
|
574
|
-
* Strictly for internal evaluation!
|
|
575
|
-
*
|
|
576
|
-
* @param {CSN.Model} csn A CSN - for things to work correctly, this is expected to be a DB transformed CSN. Plain CSN might work - or might not.
|
|
577
|
-
* @param {sqlOptions} [options={}] Options
|
|
578
|
-
* @returns {SQL[]} Array of SQL statements, tables first, views second - the resulting statements might not be a consistent, deployable state!
|
|
579
|
-
*/
|
|
580
|
-
function renderSQL(csn, options) {
|
|
581
|
-
const internalOptions = prepareOptions.to.sql(options);
|
|
582
|
-
if (!isBetaEnabled(internalOptions, 'renderSQL'))
|
|
583
|
-
throw new Error('renderSQL is only available with beta-flag "renderSQL".');
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
// Add flag so it thinks we ran through forHanaNew
|
|
587
|
-
internalOptions.forHana = true;
|
|
588
|
-
|
|
589
|
-
const sqlResult = toSqlDdl(csn, internalOptions);
|
|
590
|
-
return Object.values(flattenResultStructure(sqlResult));
|
|
591
|
-
}
|
|
592
|
-
|
|
593
596
|
module.exports = {
|
|
594
597
|
odata: publishCsnProcessor(odata, 'for.odata'),
|
|
595
598
|
cdl: publishCsnProcessor(cdl, 'to.cdl'),
|
|
@@ -598,44 +601,14 @@ module.exports = {
|
|
|
598
601
|
hdbcds: publishCsnProcessor(hdbcds, 'to.hdbcds'),
|
|
599
602
|
edm: publishCsnProcessor(edm, 'to.edm'),
|
|
600
603
|
edmx: publishCsnProcessor(edmx, 'to.edmx'),
|
|
601
|
-
|
|
602
|
-
|
|
604
|
+
/** Internal only */
|
|
605
|
+
for_sql: publishCsnProcessor(forSql, 'for.sql'),
|
|
606
|
+
for_hdi: publishCsnProcessor(forHdi, 'for.hdi'),
|
|
607
|
+
for_hdbcds: publishCsnProcessor(forHdbcds, 'for.hdbcds'),
|
|
608
|
+
/** */
|
|
603
609
|
};
|
|
604
610
|
|
|
605
611
|
|
|
606
|
-
/**
|
|
607
|
-
* Recompile the given CSN
|
|
608
|
-
*
|
|
609
|
-
* @param {object} csn Input CSN to recompile to XSN
|
|
610
|
-
* @param {object} options Options
|
|
611
|
-
* @returns {object} XSN
|
|
612
|
-
*
|
|
613
|
-
* TODO: move to lib/compiler/, consider new $recompile option, probaby issue
|
|
614
|
-
* message api-recompiled-csn there.
|
|
615
|
-
*/
|
|
616
|
-
function recompile(csn, options) {
|
|
617
|
-
// TODO: is it really a good idea to set options in the input parameter?
|
|
618
|
-
// (as long as we have the messages meddling of the option processor...)
|
|
619
|
-
// OK, I try a copy
|
|
620
|
-
options = { ...options };
|
|
621
|
-
// Explicitly set parseCdl to false because backends cannot handle
|
|
622
|
-
// the option and is only intended for CDL sources.
|
|
623
|
-
options.parseCdl = false; // TODO: delete this option
|
|
624
|
-
// Explicitly delete all toCsn options
|
|
625
|
-
delete options.toCsn;
|
|
626
|
-
/* eslint-disable global-require */
|
|
627
|
-
const { augment } = require('../json/from-csn');
|
|
628
|
-
const { compileSourcesX } = require('../compiler');
|
|
629
|
-
/* eslint-enable global-require */
|
|
630
|
-
const file = csn.$location && csn.$location.file &&
|
|
631
|
-
csn.$location.file.replace(/[.]cds$/, '.cds.csn') || '<recompile>.csn';
|
|
632
|
-
const xsn = augment(csn, file, options); // in-place
|
|
633
|
-
const compiled = compileSourcesX( { [file]: xsn }, { ...options, $recompile: true } );
|
|
634
|
-
if (options.messages)
|
|
635
|
-
deduplicateMessages(options.messages);
|
|
636
|
-
return compiled;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
612
|
/**
|
|
640
613
|
* @param {any} processor CSN processor
|
|
641
614
|
* @param {string} _name Name of the processor
|
|
@@ -675,7 +648,7 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
675
648
|
const { info } = makeMessageFunction( csn, options, 'compile' );
|
|
676
649
|
info( 'api-recompiled-csn', emptyLocation('csn.json'), {}, 'CSN input had to be recompiled' );
|
|
677
650
|
// next line to be replaced by CSN parser call which reads the CSN object
|
|
678
|
-
const xsn =
|
|
651
|
+
const xsn = recompileX(csn, options);
|
|
679
652
|
const recompiledCsn = compactModel(xsn);
|
|
680
653
|
return processor( recompiledCsn, options, ...args );
|
|
681
654
|
}
|
|
@@ -707,6 +680,12 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
707
680
|
* @typedef {'plain' | 'quoted' | 'hdbcds' } NamingMode
|
|
708
681
|
*/
|
|
709
682
|
|
|
683
|
+
/**
|
|
684
|
+
* Available SQL change modes
|
|
685
|
+
*
|
|
686
|
+
* @typedef {'alter' | 'drop' } SqlChangeMode
|
|
687
|
+
*/
|
|
688
|
+
|
|
710
689
|
/**
|
|
711
690
|
* Available oData versions
|
|
712
691
|
*
|
|
@@ -749,6 +728,8 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
749
728
|
*
|
|
750
729
|
* @typedef {object} hdiOptions
|
|
751
730
|
* @property {NamingMode} [sqlMapping='plain'] Naming mode to use
|
|
731
|
+
* @property {SqlChangeMode} [sqlChangeMode='alter'] SQL change mode to use (for changed columns)
|
|
732
|
+
* @property {boolean} [allowCsnDowngrade=false] Allow downgrades of CSN major version (for modelCompare)
|
|
752
733
|
* @property {object} [beta] Enable experimental features - not for productive use!
|
|
753
734
|
* @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
|
|
754
735
|
* @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
|
package/lib/api/options.js
CHANGED
|
@@ -10,15 +10,18 @@ const publicOptionsNewAPI = [
|
|
|
10
10
|
// GENERAL
|
|
11
11
|
'beta',
|
|
12
12
|
'deprecated',
|
|
13
|
+
'addTextsLanguageAssoc',
|
|
13
14
|
'localizedLanguageFallback', // why can't I define the option type here?
|
|
14
15
|
'severities',
|
|
15
16
|
'messages',
|
|
16
17
|
'withLocations',
|
|
17
18
|
'defaultStringLength',
|
|
19
|
+
'csnFlavor',
|
|
18
20
|
// DB
|
|
19
21
|
'sqlDialect',
|
|
20
22
|
'sqlMapping',
|
|
21
23
|
'sqlChangeMode',
|
|
24
|
+
'allowCsnDowngrade',
|
|
22
25
|
'joinfk',
|
|
23
26
|
'magicVars',
|
|
24
27
|
// ODATA
|
|
@@ -49,6 +52,7 @@ const privateOptions = [
|
|
|
49
52
|
'skipDbConstraints',
|
|
50
53
|
'noRecompile',
|
|
51
54
|
'internalMsg',
|
|
55
|
+
'disableHanaComments', // in case of issues with hana comment rendering
|
|
52
56
|
'dependentAutoexposed', // deprecated, no effect - TODO: safe to remove?
|
|
53
57
|
'longAutoexposed', // deprecated, no effect - TODO: safe to remove?
|
|
54
58
|
'localizedWithoutCoalesce', // deprecated version of 'localizedLanguageFallback',
|
|
@@ -66,10 +70,11 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
|
|
|
66
70
|
* @param {FlatOptions} [hardRequire={}] Hard requirements to enforce
|
|
67
71
|
* @param {object} [customValidators] Custom validations to run instead of defaults
|
|
68
72
|
* @param {string[]} [combinationValidators] Option combinations to validate
|
|
73
|
+
* @param {string} moduleName The called module, e.g. 'for.odata', 'to.hdi'. Needed to initialize the message functions
|
|
69
74
|
* @returns {TranslatedOptions} General cds options
|
|
70
75
|
*/
|
|
71
76
|
function translateOptions(input = {}, defaults = {}, hardRequire = {},
|
|
72
|
-
customValidators = {}, combinationValidators = []) {
|
|
77
|
+
customValidators = {}, combinationValidators = [], moduleName = '') {
|
|
73
78
|
const options = Object.assign({}, defaults);
|
|
74
79
|
const inputOptionNames = Object.keys(input);
|
|
75
80
|
for (const name of overallOptions) {
|
|
@@ -88,6 +93,7 @@ function translateOptions(input = {}, defaults = {}, hardRequire = {},
|
|
|
88
93
|
// Validate the filtered input options
|
|
89
94
|
// only "new-style" options are here
|
|
90
95
|
validate(options,
|
|
96
|
+
moduleName,
|
|
91
97
|
// TODO: is there a better place to specify the type of option values?
|
|
92
98
|
Object.assign( {
|
|
93
99
|
localizedLanguageFallback: generateStringValidator([ 'none', 'coalesce' ]),
|
|
@@ -139,11 +145,11 @@ function translateOptions(input = {}, defaults = {}, hardRequire = {},
|
|
|
139
145
|
|
|
140
146
|
module.exports = {
|
|
141
147
|
to: {
|
|
142
|
-
cdl: options => translateOptions(options),
|
|
148
|
+
cdl: options => translateOptions(options, undefined, undefined, undefined, undefined, 'to.cdl'),
|
|
143
149
|
sql: (options) => {
|
|
144
150
|
const hardOptions = { src: 'sql' };
|
|
145
151
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'plain' };
|
|
146
|
-
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ]);
|
|
152
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ], 'to.sql');
|
|
147
153
|
|
|
148
154
|
const result = Object.assign({}, processed);
|
|
149
155
|
result.toSql = Object.assign({}, processed);
|
|
@@ -153,7 +159,7 @@ module.exports = {
|
|
|
153
159
|
hdi: (options) => {
|
|
154
160
|
const hardOptions = { src: 'hdi' };
|
|
155
161
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
|
|
156
|
-
const processed = translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) });
|
|
162
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdi');
|
|
157
163
|
|
|
158
164
|
const result = Object.assign({}, processed);
|
|
159
165
|
result.toSql = Object.assign({}, processed);
|
|
@@ -162,17 +168,17 @@ module.exports = {
|
|
|
162
168
|
},
|
|
163
169
|
hdbcds: (options) => {
|
|
164
170
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
|
|
165
|
-
const processed = translateOptions(options, defaultOptions, {}, { sqlDialect: generateStringValidator([ 'hana' ]) });
|
|
171
|
+
const processed = translateOptions(options, defaultOptions, {}, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdbcds');
|
|
166
172
|
|
|
167
173
|
const result = Object.assign({}, processed);
|
|
168
|
-
result.
|
|
174
|
+
result.forHana = Object.assign({}, processed);
|
|
169
175
|
|
|
170
176
|
return result;
|
|
171
177
|
},
|
|
172
178
|
edm: (options) => {
|
|
173
179
|
const hardOptions = { json: true, combined: true };
|
|
174
180
|
const defaultOptions = { odataVersion: 'v4', odataFormat: 'flat' };
|
|
175
|
-
const processed = translateOptions(options, defaultOptions, hardOptions, { odataVersion: generateStringValidator([ 'v4' ]) }, [ 'valid-structured' ]);
|
|
181
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, { odataVersion: generateStringValidator([ 'v4' ]) }, [ 'valid-structured' ], 'to.edm');
|
|
176
182
|
|
|
177
183
|
const result = Object.assign({}, processed);
|
|
178
184
|
result.toOdata = Object.assign({}, processed);
|
|
@@ -184,7 +190,7 @@ module.exports = {
|
|
|
184
190
|
const defaultOptions = {
|
|
185
191
|
odataVersion: 'v4', odataFormat: 'flat',
|
|
186
192
|
};
|
|
187
|
-
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'valid-structured' ]);
|
|
193
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'valid-structured' ], 'to.edmx');
|
|
188
194
|
|
|
189
195
|
const result = Object.assign({}, processed);
|
|
190
196
|
result.toOdata = Object.assign({}, processed);
|
|
@@ -196,7 +202,7 @@ module.exports = {
|
|
|
196
202
|
|
|
197
203
|
odata: (options) => {
|
|
198
204
|
const defaultOptions = { odataVersion: 'v4', odataFormat: 'flat' };
|
|
199
|
-
const processed = translateOptions(options, defaultOptions, undefined, undefined, [ 'valid-structured' ]);
|
|
205
|
+
const processed = translateOptions(options, defaultOptions, undefined, undefined, [ 'valid-structured' ], 'for.odata');
|
|
200
206
|
|
|
201
207
|
const result = Object.assign({}, processed);
|
|
202
208
|
result.toOdata = Object.assign({}, processed);
|
|
@@ -206,10 +212,10 @@ module.exports = {
|
|
|
206
212
|
},
|
|
207
213
|
hana: (options) => {
|
|
208
214
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
|
|
209
|
-
const processed = translateOptions(options, defaultOptions);
|
|
215
|
+
const processed = translateOptions(options, defaultOptions, undefined, undefined, undefined, 'for.hana');
|
|
210
216
|
|
|
211
217
|
const result = Object.assign({}, processed);
|
|
212
|
-
result.
|
|
218
|
+
result.forHana = Object.assign({}, processed);
|
|
213
219
|
|
|
214
220
|
|
|
215
221
|
return result;
|