@sap/cds-compiler 2.12.0 → 2.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +221 -15
- package/bin/cdsc.js +125 -50
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +47 -84
- package/lib/api/options.js +5 -6
- package/lib/api/validate.js +6 -11
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +114 -18
- package/lib/base/messages.js +101 -90
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +177 -123
- package/lib/checks/annotationsOData.js +12 -33
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +6 -11
- package/lib/compiler/assert-consistency.js +6 -3
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +19 -6
- package/lib/compiler/checks.js +23 -60
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1151 -0
- package/lib/compiler/extend.js +1000 -0
- package/lib/compiler/finalize-parse-cdl.js +237 -0
- package/lib/compiler/index.js +107 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1227 -0
- package/lib/compiler/propagator.js +114 -46
- package/lib/compiler/resolve.js +1521 -0
- package/lib/compiler/shared.js +126 -65
- package/lib/compiler/tweak-assocs.js +535 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -24
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +219 -100
- package/lib/edm/edm.js +302 -230
- package/lib/edm/edmPreprocessor.js +554 -419
- package/lib/edm/edmUtils.js +138 -44
- package/lib/gen/Dictionary.json +100 -19
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5765 -4480
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +15 -3
- package/lib/json/to-csn.js +126 -68
- package/lib/language/docCommentParser.js +4 -4
- package/lib/language/genericAntlrParser.js +123 -5
- package/lib/language/language.g4 +355 -156
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +486 -59
- package/lib/main.js +41 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +252 -156
- package/lib/model/csnUtils.js +384 -297
- package/lib/model/enrichCsn.js +71 -29
- package/lib/model/revealInternalProperties.js +29 -8
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +23 -18
- package/lib/optionProcessor.js +63 -26
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +897 -947
- package/lib/render/toHdbcds.js +205 -257
- package/lib/render/toSql.js +264 -225
- package/lib/render/utils/common.js +136 -25
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +3 -1
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +104 -306
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +58 -53
- package/lib/transform/db/expansion.js +60 -33
- package/lib/transform/db/flattening.js +582 -104
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +66 -13
- package/lib/transform/db/views.js +11 -7
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +109 -208
- package/lib/transform/forOdataNew.js +59 -212
- package/lib/transform/localized.js +46 -26
- package/lib/transform/odata/toFinalBaseType.js +85 -11
- package/lib/transform/odata/typesExposure.js +147 -199
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +44 -33
- package/lib/transform/translateAssocsToJoins.js +3 -20
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +172 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/moduleResolve.js +13 -6
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -290
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
- package/lib/transform/universalCsnEnricher.js +0 -237
|
@@ -11,9 +11,25 @@ Note: `deprecated` features are listed in this ChangeLog just for information.
|
|
|
11
11
|
**When the `deprecated` option is set, the `beta` option is ignored,
|
|
12
12
|
and several new features are not available.**
|
|
13
13
|
|
|
14
|
+
## Version 2.XX.YY - 2022-MM-DD
|
|
15
|
+
|
|
16
|
+
### Added `redirectInSubQueries`
|
|
17
|
+
|
|
18
|
+
When this option is set, we auto-redirect associations and composition also in
|
|
19
|
+
non-main queries, sometimes without rewriting the `keys`/`on` (there will be no
|
|
20
|
+
fix for this).
|
|
21
|
+
|
|
22
|
+
### Added `oldVirtualNotNullPropagation`
|
|
23
|
+
|
|
24
|
+
When this option is set, we do not propagate `notNull` along types.
|
|
25
|
+
Additionally, we propagate `notNull` and `virtual` from a query source element
|
|
26
|
+
to the sub elements of a query entity element, even if the property is not
|
|
27
|
+
propagated to the query entity element itself (like with type references).
|
|
28
|
+
|
|
29
|
+
|
|
14
30
|
## Version 2.2.0
|
|
15
31
|
|
|
16
|
-
|
|
32
|
+
### Added `noScopedRedirections`
|
|
17
33
|
|
|
18
34
|
When this option is set, the definition scope is not taken into account when
|
|
19
35
|
trying to find an implicit redirection target. Setting the following
|
|
@@ -21,18 +37,18 @@ deprecated options also switches off scoped redirections (additionally to their
|
|
|
21
37
|
other effect): `noElementsExpansion`, `generatedEntityNameWithUnderscore`,
|
|
22
38
|
`shortAutoexposed`, `longAutoexposed`, `noInheritedAutoexposeViaComposition`.
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
### Added `noInheritedAutoexposeViaComposition`
|
|
25
41
|
|
|
26
42
|
When this option is set, only entities directly specified after `Composition of` are
|
|
27
43
|
auto-exposed, not entities used as target via explicit or implicit `redirected to`.
|
|
28
44
|
|
|
29
45
|
## Version 2.0.16
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
### Added `downgradableErrors`
|
|
32
48
|
|
|
33
49
|
Allow to change the severity of some errors which should stay to be an error.
|
|
34
50
|
|
|
35
|
-
|
|
51
|
+
### Added `shortAutoexposed`
|
|
36
52
|
|
|
37
53
|
When this option is set (and `generatedEntityNameWithUnderscore`), the names of
|
|
38
54
|
autoexposed entities are calculated according to the default compiler v1
|
|
@@ -40,13 +56,13 @@ behavior (without v1 options `dependentAutoexposed` and `longAutoexposed`).
|
|
|
40
56
|
|
|
41
57
|
## Version 2.0.10
|
|
42
58
|
|
|
43
|
-
|
|
59
|
+
### Added `longAutoexposed`
|
|
44
60
|
|
|
45
61
|
When this option is set (and `generatedEntityNameWithUnderscore`),
|
|
46
62
|
the names of autoexposed entities are calculated according to the
|
|
47
63
|
compiler v1 option `longAutoexposed`.
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
### Added `generatedEntityNameWithUnderscore`
|
|
50
66
|
|
|
51
67
|
Keep using `_` is separator for generated autoexposed entities and for entities
|
|
52
68
|
created for managed compositions. It also disables a definition `A.B.C` if `A`
|
package/doc/NameResolution.md
CHANGED
|
@@ -22,22 +22,27 @@ others might want to [skip the introduction](#design-principles).
|
|
|
22
22
|
|
|
23
23
|
## Table of Contents
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
<!-- toc: start -->
|
|
26
|
+
|
|
27
|
+
1. [Table of Contents](#table-of-contents)
|
|
28
|
+
2. [Introduction](#introduction)
|
|
29
|
+
1. [Background: SQL](#background-sql)
|
|
30
|
+
2. [Background: modern programming languages](#background-modern-programming-languages)
|
|
31
|
+
3. [Design Principles](#design-principles)
|
|
32
|
+
4. [Name Resolution - the Basics](#name-resolution---the-basics)
|
|
33
|
+
1. [Common rules](#common-rules)
|
|
34
|
+
2. [Resolving paths](#resolving-paths)
|
|
35
|
+
3. [Navigation environment](#navigation-environment)
|
|
36
|
+
5. [References to main artifacts](#references-to-main-artifacts)
|
|
37
|
+
6. [Values and references to elements](#values-and-references-to-elements)
|
|
38
|
+
1. [References in queries](#references-in-queries)
|
|
39
|
+
2. [References to sibling elements](#references-to-sibling-elements)
|
|
40
|
+
3. [Other element references](#other-element-references)
|
|
41
|
+
7. [Paths as annotation values](#paths-as-annotation-values)
|
|
42
|
+
8. [Differences to HANA-CDS](#differences-to-hana-cds)
|
|
43
|
+
9. [Summary](#summary)
|
|
44
|
+
|
|
45
|
+
<!-- toc: end -->
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
## Introduction
|
package/lib/api/main.js
CHANGED
|
@@ -33,8 +33,10 @@ const propertyToCheck = {
|
|
|
33
33
|
odata: 'toOdata',
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
const {
|
|
36
|
+
const { cloneCsnNonDict } = require('../model/csnUtils');
|
|
37
37
|
const { toHdbcdsSource } = require('../render/toHdbcds');
|
|
38
|
+
const { ModelError } = require('../base/error');
|
|
39
|
+
const { forEach } = require('../utils/objectUtils');
|
|
38
40
|
|
|
39
41
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
40
42
|
const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
|
|
@@ -90,7 +92,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
90
92
|
// Not able to check
|
|
91
93
|
return;
|
|
92
94
|
}
|
|
93
|
-
const { error, warning,
|
|
95
|
+
const { error, warning, throwWithAnyError } = makeMessageFunction(csn, options, module);
|
|
94
96
|
|
|
95
97
|
for (const name of relevantOptionNames ) {
|
|
96
98
|
if (options[name] !== csn.meta.options[name])
|
|
@@ -102,7 +104,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
102
104
|
warning('options-mismatch-pretransformed-csn', null, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
throwWithAnyError();
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
@@ -115,7 +117,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
115
117
|
* @returns {boolean} Return true if it is pre-transformed
|
|
116
118
|
*/
|
|
117
119
|
function isPreTransformed(csn, transformation) {
|
|
118
|
-
return csn.meta && csn.meta.transformation === transformation;
|
|
120
|
+
return csn && csn.meta && csn.meta.transformation === transformation;
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
/**
|
|
@@ -152,7 +154,7 @@ function odata(csn, options = {}) {
|
|
|
152
154
|
*/
|
|
153
155
|
function cdl(csn, externalOptions = {}) {
|
|
154
156
|
const internalOptions = prepareOptions.to.cdl(externalOptions);
|
|
155
|
-
const { result } = backends.toCdlWithCsn(
|
|
157
|
+
const { result } = backends.toCdlWithCsn(cloneCsnNonDict(csn, internalOptions), internalOptions);
|
|
156
158
|
return result;
|
|
157
159
|
}
|
|
158
160
|
/**
|
|
@@ -173,7 +175,7 @@ function forSql(csn, options = {}) {
|
|
|
173
175
|
* Transform a CSN like to.hdi
|
|
174
176
|
*
|
|
175
177
|
* @param {CSN.Model} csn Plain input CSN
|
|
176
|
-
* @param {
|
|
178
|
+
* @param {HdiOptions} [options={}] Options
|
|
177
179
|
* @returns {CSN.Model} CSN transformed like to.hdi
|
|
178
180
|
* @private
|
|
179
181
|
*/
|
|
@@ -186,7 +188,7 @@ function forHdi(csn, options = {}) {
|
|
|
186
188
|
* Transform a CSN like to.hdbcds
|
|
187
189
|
*
|
|
188
190
|
* @param {CSN.Model} csn Plain input CSN
|
|
189
|
-
* @param {
|
|
191
|
+
* @param {HdbcdsOptions} [options={}] Options
|
|
190
192
|
* @returns {CSN.Model} CSN transformed like to.hdbcds
|
|
191
193
|
* @private
|
|
192
194
|
*/
|
|
@@ -224,7 +226,7 @@ function sql(csn, options = {}) {
|
|
|
224
226
|
* Process the given CSN into HDI artifacts.
|
|
225
227
|
*
|
|
226
228
|
* @param {CSN.Model} csn A clean input CSN
|
|
227
|
-
* @param {
|
|
229
|
+
* @param {HdiOptions} [options={}] Options
|
|
228
230
|
* @returns {HDIArtifacts} { <filename>:<content>, ...}
|
|
229
231
|
*/
|
|
230
232
|
function hdi(csn, options = {}) {
|
|
@@ -247,19 +249,19 @@ function hdi(csn, options = {}) {
|
|
|
247
249
|
const flat = flattenResultStructure(intermediateResult);
|
|
248
250
|
|
|
249
251
|
const nameMapping = Object.create(null);
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
+
const sqlArtifactsWithCSNNamesToSort = Object.create(null);
|
|
253
|
+
const sqlArtifactsNotToSort = Object.create(null);
|
|
252
254
|
|
|
253
|
-
|
|
255
|
+
forEach(flat, (key) => {
|
|
254
256
|
const artifactNameLikeInCsn = key.replace(/\.[^/.]+$/, '');
|
|
255
257
|
nameMapping[artifactNameLikeInCsn] = key;
|
|
256
258
|
if (key.endsWith('.hdbtable') || key.endsWith('.hdbview'))
|
|
257
|
-
|
|
259
|
+
sqlArtifactsWithCSNNamesToSort[artifactNameLikeInCsn] = flat[key];
|
|
258
260
|
else
|
|
259
|
-
|
|
261
|
+
sqlArtifactsNotToSort[key] = flat[key];
|
|
260
262
|
});
|
|
261
263
|
|
|
262
|
-
const sorted = sortViews({ sql:
|
|
264
|
+
const sorted = sortViews({ sql: sqlArtifactsWithCSNNamesToSort, csn: sqlCSN })
|
|
263
265
|
.filter(obj => obj.sql)
|
|
264
266
|
.reduce((previous, current) => {
|
|
265
267
|
const hdiArtifactName = remapName(nameMapping[current.name], sqlCSN, k => !k.endsWith('.hdbindex'));
|
|
@@ -267,9 +269,9 @@ function hdi(csn, options = {}) {
|
|
|
267
269
|
return previous;
|
|
268
270
|
}, Object.create(null));
|
|
269
271
|
|
|
270
|
-
// now add the not-sorted stuff, like
|
|
271
|
-
|
|
272
|
-
sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] =
|
|
272
|
+
// now add the not-sorted stuff, like indices
|
|
273
|
+
forEach(sqlArtifactsNotToSort, (key) => {
|
|
274
|
+
sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlArtifactsNotToSort[key];
|
|
273
275
|
});
|
|
274
276
|
|
|
275
277
|
return sorted;
|
|
@@ -290,10 +292,10 @@ function hdi(csn, options = {}) {
|
|
|
290
292
|
function remapNames(dict, csn, filter) {
|
|
291
293
|
const result = Object.create(null);
|
|
292
294
|
|
|
293
|
-
|
|
295
|
+
forEach(dict, (key, value) => {
|
|
294
296
|
const name = remapName(key, csn, filter);
|
|
295
297
|
result[name] = value;
|
|
296
|
-
}
|
|
298
|
+
});
|
|
297
299
|
|
|
298
300
|
return result;
|
|
299
301
|
}
|
|
@@ -325,7 +327,7 @@ function remapName(key, csn, filter = () => true) {
|
|
|
325
327
|
* Note: Only supports changes in entities (not views etc.) compiled/rendered as HANA-CSN/SQL.
|
|
326
328
|
*
|
|
327
329
|
* @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
|
|
328
|
-
* @param {
|
|
330
|
+
* @param {HdiOptions} options Options
|
|
329
331
|
* @param {CSN.Model} beforeImage A HANA-transformed CSN representing the "before-image", or null in case no such image
|
|
330
332
|
* is known, i.e. for the very first migration step
|
|
331
333
|
* @returns {object} - afterImage: The desired after-image in HANA-CSN format
|
|
@@ -346,8 +348,8 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
346
348
|
* This is for backward compatibility with @sap/cds@4.5.(2…3).
|
|
347
349
|
*
|
|
348
350
|
* @todo Remove in cds-compiler@2.x
|
|
349
|
-
* @param {
|
|
350
|
-
* @param {CSN.Model
|
|
351
|
+
* @param {HdiOptions|CSN.Model} inputOptions Options or CSN image
|
|
352
|
+
* @param {HdiOptions|CSN.Model} inputBeforeImage CSN image or options
|
|
351
353
|
* @returns {Array} Array where the real options come first
|
|
352
354
|
*/
|
|
353
355
|
function backwardCompatible(inputOptions, inputBeforeImage) {
|
|
@@ -395,15 +397,15 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
395
397
|
*/
|
|
396
398
|
function createDefinitions() {
|
|
397
399
|
const result = [];
|
|
398
|
-
|
|
400
|
+
forEach(hdbkinds, (kind, artifacts) => {
|
|
399
401
|
const suffix = `.${ kind }`;
|
|
400
|
-
|
|
402
|
+
forEach(artifacts, (name, sqlStatement) => {
|
|
401
403
|
if ( kind !== 'hdbindex' )
|
|
402
404
|
result.push({ name: getFileName(name, afterImage), suffix, sql: sqlStatement });
|
|
403
405
|
else
|
|
404
406
|
result.push({ name, suffix, sql: sqlStatement });
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
+
});
|
|
408
|
+
});
|
|
407
409
|
return result;
|
|
408
410
|
}
|
|
409
411
|
/**
|
|
@@ -413,9 +415,7 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
413
415
|
*/
|
|
414
416
|
function createDeletions() {
|
|
415
417
|
const result = [];
|
|
416
|
-
|
|
417
|
-
result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' });
|
|
418
|
-
|
|
418
|
+
forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
|
|
419
419
|
return result;
|
|
420
420
|
}
|
|
421
421
|
/**
|
|
@@ -425,9 +425,7 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
425
425
|
*/
|
|
426
426
|
function createMigrations() {
|
|
427
427
|
const result = [];
|
|
428
|
-
|
|
429
|
-
result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset });
|
|
430
|
-
|
|
428
|
+
forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
|
|
431
429
|
return result;
|
|
432
430
|
}
|
|
433
431
|
}
|
|
@@ -438,7 +436,7 @@ hdi.migration = hdiMigration;
|
|
|
438
436
|
* Process the given CSN into HDBCDS artifacts.
|
|
439
437
|
*
|
|
440
438
|
* @param {any} csn A clean input CSN
|
|
441
|
-
* @param {
|
|
439
|
+
* @param {HdbcdsOptions} [options={}] Options
|
|
442
440
|
* @returns {HDBCDS} { <filename>:<content>, ...}
|
|
443
441
|
*/
|
|
444
442
|
function hdbcds(csn, options = {}) {
|
|
@@ -585,12 +583,13 @@ function edmxall(csn, options = {}) {
|
|
|
585
583
|
*/
|
|
586
584
|
function flattenResultStructure(toProcess) {
|
|
587
585
|
const result = {};
|
|
588
|
-
|
|
586
|
+
forEach(toProcess, (fileType, artifacts) => {
|
|
589
587
|
if (fileType === 'messages')
|
|
590
|
-
|
|
591
|
-
|
|
588
|
+
return;
|
|
589
|
+
forEach(artifacts, (filename) => {
|
|
592
590
|
result[`${ filename }.${ fileType }`] = artifacts[filename];
|
|
593
|
-
|
|
591
|
+
});
|
|
592
|
+
});
|
|
594
593
|
|
|
595
594
|
return result;
|
|
596
595
|
}
|
|
@@ -643,12 +642,18 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
643
642
|
return processor( csn, options, ...args );
|
|
644
643
|
}
|
|
645
644
|
catch (err) {
|
|
646
|
-
if (err instanceof CompilationError || options.noRecompile)
|
|
647
|
-
|
|
645
|
+
if (err instanceof CompilationError || options.noRecompile || isPreTransformed(csn, 'odata')) // we cannot recompile a pre-transformed CSN
|
|
646
|
+
throw err;
|
|
647
|
+
|
|
648
|
+
if (options.testMode && !(err instanceof TypeError) &&
|
|
649
|
+
!(err instanceof ModelError))
|
|
648
650
|
throw err;
|
|
649
651
|
|
|
650
652
|
const { info } = makeMessageFunction( csn, options, 'compile' );
|
|
651
|
-
info( 'api-recompiled-csn', emptyLocation('csn.json'), {}, 'CSN input had to be recompiled' );
|
|
653
|
+
const msg = info( 'api-recompiled-csn', emptyLocation('csn.json'), {}, 'CSN input had to be recompiled' );
|
|
654
|
+
if (options.internalMsg)
|
|
655
|
+
msg.error = err; // Attach original error
|
|
656
|
+
|
|
652
657
|
// next line to be replaced by CSN parser call which reads the CSN object
|
|
653
658
|
const xsn = recompileX(csn, options);
|
|
654
659
|
const recompiledCsn = compactModel(xsn);
|
|
@@ -682,12 +687,6 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
682
687
|
* @typedef {'plain' | 'quoted' | 'hdbcds' } NamingMode
|
|
683
688
|
*/
|
|
684
689
|
|
|
685
|
-
/**
|
|
686
|
-
* Available SQL change modes
|
|
687
|
-
*
|
|
688
|
-
* @typedef {'alter' | 'drop' } SqlChangeMode
|
|
689
|
-
*/
|
|
690
|
-
|
|
691
690
|
/**
|
|
692
691
|
* Available oData versions
|
|
693
692
|
*
|
|
@@ -700,42 +699,6 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
700
699
|
* @typedef { 'structured' | 'flat' } oDataFormat
|
|
701
700
|
*/
|
|
702
701
|
|
|
703
|
-
/**
|
|
704
|
-
* Generally available options
|
|
705
|
-
*
|
|
706
|
-
* @typedef {object} Options
|
|
707
|
-
* @property {object} [beta] Enable experimental features - not for productive use!
|
|
708
|
-
* @property {boolean} [dependentAutoexposed=false] For dependent autoexposed entities (managed compositions, texts entity), follow name of base entity
|
|
709
|
-
* @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
|
|
710
|
-
* @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
|
|
711
|
-
* @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
|
|
712
|
-
*/
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
* Options available for to.hdi
|
|
716
|
-
*
|
|
717
|
-
* @typedef {object} hdiOptions
|
|
718
|
-
* @property {NamingMode} [sqlMapping='plain'] Naming mode to use
|
|
719
|
-
* @property {SqlChangeMode} [sqlChangeMode='alter'] SQL change mode to use (for changed columns)
|
|
720
|
-
* @property {boolean} [allowCsnDowngrade=false] Allow downgrades of CSN major version (for modelCompare)
|
|
721
|
-
* @property {object} [beta] Enable experimental features - not for productive use!
|
|
722
|
-
* @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
|
|
723
|
-
* @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
|
|
724
|
-
* @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
|
|
725
|
-
*/
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Options available for to.hdbcds
|
|
729
|
-
*
|
|
730
|
-
* @typedef {object} hdbcdsOptions
|
|
731
|
-
* @property {NamingMode} [sqlMapping='plain'] Naming mode to use
|
|
732
|
-
* @property {object} [beta] Enable experimental features - not for productive use!
|
|
733
|
-
* @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
|
|
734
|
-
* @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
|
|
735
|
-
* @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
|
|
736
|
-
*/
|
|
737
|
-
|
|
738
|
-
|
|
739
702
|
/**
|
|
740
703
|
* A fresh (just compiled, not transformed) CSN
|
|
741
704
|
*
|
|
@@ -755,13 +718,13 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
755
718
|
*/
|
|
756
719
|
|
|
757
720
|
/**
|
|
758
|
-
* A map of { <file.hdbcds>:<content> }.
|
|
721
|
+
* A map of { <file.hdbcds|hdbconstraint>:<content> }.
|
|
759
722
|
*
|
|
760
723
|
* @typedef {object} HDBCDS
|
|
761
724
|
*/
|
|
762
725
|
|
|
763
726
|
/**
|
|
764
|
-
* A map of { <file.hdbtable
|
|
727
|
+
* A map of { <file.hdbtable|hdbview|hdbconstraint...>:<content> }.
|
|
765
728
|
*
|
|
766
729
|
* @typedef {object} HDIArtifacts
|
|
767
730
|
*/
|
package/lib/api/options.js
CHANGED
|
@@ -49,7 +49,7 @@ const privateOptions = [
|
|
|
49
49
|
'traceParserAmb',
|
|
50
50
|
'testMode',
|
|
51
51
|
'testSortCsn',
|
|
52
|
-
'
|
|
52
|
+
'constraintsInCreateTable',
|
|
53
53
|
'integrityNotEnforced',
|
|
54
54
|
'integrityNotValidated',
|
|
55
55
|
'assertIntegrity',
|
|
@@ -80,13 +80,12 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
|
|
|
80
80
|
function translateOptions(input = {}, defaults = {}, hardRequire = {},
|
|
81
81
|
customValidators = {}, combinationValidators = [], moduleName = '') {
|
|
82
82
|
const options = Object.assign({}, defaults);
|
|
83
|
-
const inputOptionNames = Object.keys(input);
|
|
84
83
|
for (const name of overallOptions) {
|
|
85
84
|
// Ensure that arrays are not passed as a reference!
|
|
86
85
|
// This caused issues with the way messages are handled in processMessages
|
|
87
|
-
if (Array.isArray(input[name])
|
|
86
|
+
if (Array.isArray(input[name]))
|
|
88
87
|
options[name] = [ ...input[name] ];
|
|
89
|
-
else if (
|
|
88
|
+
else if (Object.hasOwnProperty.call(input, name))
|
|
90
89
|
options[name] = input[name];
|
|
91
90
|
}
|
|
92
91
|
|
|
@@ -158,7 +157,7 @@ module.exports = {
|
|
|
158
157
|
sql: (options) => {
|
|
159
158
|
const hardOptions = { src: 'sql' };
|
|
160
159
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'plain' };
|
|
161
|
-
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming'
|
|
160
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ], 'to.sql');
|
|
162
161
|
|
|
163
162
|
const result = Object.assign({}, processed);
|
|
164
163
|
result.toSql = Object.assign({}, processed);
|
|
@@ -166,7 +165,7 @@ module.exports = {
|
|
|
166
165
|
return result;
|
|
167
166
|
},
|
|
168
167
|
hdi: (options) => {
|
|
169
|
-
const hardOptions = { src: 'hdi'
|
|
168
|
+
const hardOptions = { src: 'hdi' };
|
|
170
169
|
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
|
|
171
170
|
const processed = translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdi');
|
|
172
171
|
|
package/lib/api/validate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { makeMessageFunction } = require('../base/messages');
|
|
4
|
+
const { forEach } = require('../utils/objectUtils');
|
|
4
5
|
|
|
5
6
|
/* eslint-disable arrow-body-style */
|
|
6
7
|
const booleanValidator = {
|
|
@@ -142,11 +143,6 @@ const allCombinationValidators = {
|
|
|
142
143
|
severity: 'warning',
|
|
143
144
|
getMessage: () => 'Option "beta" was used. This option should not be used in productive scenarios!',
|
|
144
145
|
},
|
|
145
|
-
'constraints-as-alter-sqlite': {
|
|
146
|
-
validate: options => options.constraintsAsAlter && options.sqlDialect && options.sqlDialect === 'sqlite',
|
|
147
|
-
severity: 'warning',
|
|
148
|
-
getMessage: options => `Option 'constraintsAsAlter' is ignored for sqlDialect '${ options.sqlDialect }'`,
|
|
149
|
-
},
|
|
150
146
|
};
|
|
151
147
|
/* eslint-disable jsdoc/no-undefined-types */
|
|
152
148
|
/**
|
|
@@ -164,16 +160,15 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
|
|
|
164
160
|
// TODO: issuing messages in this function looks very strange...
|
|
165
161
|
{
|
|
166
162
|
const messageCollector = { messages: [] };
|
|
167
|
-
const { error,
|
|
163
|
+
const { error, throwWithAnyError } = makeMessageFunction(null, messageCollector, moduleName);
|
|
168
164
|
|
|
169
|
-
|
|
170
|
-
const optionValue = options[optionName];
|
|
165
|
+
forEach(options, (optionName, optionValue) => {
|
|
171
166
|
const validator = customValidators[optionName] || validators[optionName] || booleanValidator;
|
|
172
167
|
|
|
173
168
|
if (!validator.validate(optionValue))
|
|
174
169
|
error('invalid-option', null, {}, `Expected option "${ optionName }" to have "${ validator.expected(optionValue) }". Found: "${ validator.found(optionValue) }"`);
|
|
175
|
-
}
|
|
176
|
-
|
|
170
|
+
});
|
|
171
|
+
throwWithAnyError();
|
|
177
172
|
}
|
|
178
173
|
|
|
179
174
|
const message = makeMessageFunction(null, options, moduleName);
|
|
@@ -184,7 +179,7 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
|
|
|
184
179
|
message[combinationValidator.severity]('invalid-option-combination', null, {}, combinationValidator.getMessage(options));
|
|
185
180
|
}
|
|
186
181
|
|
|
187
|
-
message.
|
|
182
|
+
message.throwWithAnyError();
|
|
188
183
|
}
|
|
189
184
|
/* eslint-enable jsdoc/no-undefined-types */
|
|
190
185
|
|
package/lib/backends.js
CHANGED
|
@@ -279,7 +279,7 @@ function transformSQLOptions(model, options) {
|
|
|
279
279
|
|
|
280
280
|
if(options.toSql.dialect !== 'hana') {
|
|
281
281
|
// CDXCORE-465, 'quoted' and 'hdbcds' are to be used in combination with dialect 'hana' only
|
|
282
|
-
if(
|
|
282
|
+
if (options.toSql.names === 'quoted' || options.toSql.names === 'hdbcds') {
|
|
283
283
|
error(null, null, `Option "{ toSql.dialect: '${options.toSql.dialect}' }" can't be combined with "{ toSql.names: '${options.toSql.names}' }"`);
|
|
284
284
|
}
|
|
285
285
|
// No non-HANA SQL for HDI
|
|
@@ -296,17 +296,17 @@ function transformSQLOptions(model, options) {
|
|
|
296
296
|
// If among the options user, user.id or user.locale are specified via the CLI or
|
|
297
297
|
// via the API, then ensure that at the end there is a user option, which is an object and has(have)
|
|
298
298
|
// "id" and/or "locale" prop(s)
|
|
299
|
-
function transformUserOption(
|
|
299
|
+
function transformUserOption(userOptions) {
|
|
300
300
|
// move the user option value under user.id if specified as a string
|
|
301
|
-
if (
|
|
302
|
-
|
|
301
|
+
if (userOptions.user && typeof userOptions.user === 'string' || userOptions.user instanceof String) {
|
|
302
|
+
userOptions.user = { id: userOptions.user };
|
|
303
303
|
}
|
|
304
304
|
// move the locale option(if provided) under user.locale
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
? Object.assign(
|
|
308
|
-
: { locale:
|
|
309
|
-
delete
|
|
305
|
+
if (userOptions.locale) {
|
|
306
|
+
userOptions.user = userOptions.user
|
|
307
|
+
? Object.assign(userOptions.user, { locale: userOptions.locale })
|
|
308
|
+
: { locale: userOptions.locale };
|
|
309
|
+
delete userOptions.locale;
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
@@ -389,7 +389,7 @@ function toRenameWithCsn(csn, options) {
|
|
|
389
389
|
let forHanaCsn = transformForHanaWithCsn(csn, mergeOptions(options, { forHana : options.toRename } ), 'to.rename');
|
|
390
390
|
// forHanaCsn looses empty contexts and services, add them again so that toRename can calculate the namespaces
|
|
391
391
|
forEachDefinition(csn, (artifact, artifactName) => {
|
|
392
|
-
if(
|
|
392
|
+
if((artifact.kind === 'context' || artifact.kind === 'service') && forHanaCsn.definitions[artifactName] === undefined) {
|
|
393
393
|
forHanaCsn.definitions[artifactName] = artifact;
|
|
394
394
|
}
|
|
395
395
|
});
|
|
@@ -416,6 +416,10 @@ function alterConstraintsWithCsn(csn, options) {
|
|
|
416
416
|
names: names || 'plain'
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
+
// Also set new-style options
|
|
420
|
+
options.sqlDialect = 'hana';
|
|
421
|
+
options.sqlMapping = names || 'plain';
|
|
422
|
+
|
|
419
423
|
// Of course we want the database constraints
|
|
420
424
|
options.assertIntegrityType = 'DB';
|
|
421
425
|
|
|
@@ -432,19 +436,7 @@ function alterConstraintsWithCsn(csn, options) {
|
|
|
432
436
|
else
|
|
433
437
|
intermediateResult = manageConstraints(forSqlCsn, mergedOptions);
|
|
434
438
|
|
|
435
|
-
|
|
436
|
-
return intermediateResult;
|
|
437
|
-
|
|
438
|
-
// if in testmode, return a string containing all the artifacts
|
|
439
|
-
let resultString = '';
|
|
440
|
-
const extension = src && src === 'hdi' ? 'hdbconstraint' : 'sql';
|
|
441
|
-
for(const id in intermediateResult){
|
|
442
|
-
const initialComment = `--$ --- ${id}.${extension} ---\n\n`;
|
|
443
|
-
resultString += initialComment;
|
|
444
|
-
resultString += intermediateResult[id];
|
|
445
|
-
resultString += '\n\n'
|
|
446
|
-
}
|
|
447
|
-
return resultString;
|
|
439
|
+
return intermediateResult;
|
|
448
440
|
}
|
|
449
441
|
|
|
450
442
|
// ----------- toCsn -----------
|
package/lib/base/dictionaries.js
CHANGED
|
@@ -89,17 +89,9 @@ function pushToDict( dict, name, entry ) {
|
|
|
89
89
|
dict[name] = [entry];
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
function forEachInDict( dict, callback ) {
|
|
93
|
-
let r = Object.create(null);
|
|
94
|
-
for (let name of Object.keys(dict))
|
|
95
|
-
r[name] = callback( dict[name], name, dict );
|
|
96
|
-
return r;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
92
|
module.exports = {
|
|
100
93
|
dictAdd, dictForEach,
|
|
101
94
|
dictAddArray,
|
|
102
95
|
pushToDict,
|
|
103
|
-
forEachInDict,
|
|
104
96
|
}
|
|
105
97
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Use this class to indicate that an internal error was noticed.
|
|
5
|
+
* In testMode, these errors do _not_ trigger a recompilation.
|
|
6
|
+
*/
|
|
7
|
+
class CompilerAssertion extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Use this class to indicate that something with the input CSN is wrong,
|
|
15
|
+
* which will be caught by the core compiler through recompiling the sources.
|
|
16
|
+
*/
|
|
17
|
+
class ModelError extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
CompilerAssertion,
|
|
25
|
+
ModelError,
|
|
26
|
+
};
|