@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.
Files changed (128) hide show
  1. package/CHANGELOG.md +221 -15
  2. package/bin/cdsc.js +125 -50
  3. package/bin/cdsse.js +2 -2
  4. package/doc/CHANGELOG_BETA.md +13 -6
  5. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  6. package/doc/NameResolution.md +21 -16
  7. package/lib/api/main.js +47 -84
  8. package/lib/api/options.js +5 -6
  9. package/lib/api/validate.js +6 -11
  10. package/lib/backends.js +15 -23
  11. package/lib/base/dictionaries.js +0 -8
  12. package/lib/base/error.js +26 -0
  13. package/lib/base/keywords.js +7 -17
  14. package/lib/base/location.js +9 -4
  15. package/lib/base/message-registry.js +114 -18
  16. package/lib/base/messages.js +101 -90
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +177 -123
  19. package/lib/checks/annotationsOData.js +12 -33
  20. package/lib/checks/arrayOfs.js +1 -34
  21. package/lib/checks/cdsPersistence.js +2 -1
  22. package/lib/checks/enricher.js +17 -1
  23. package/lib/checks/invalidTarget.js +3 -1
  24. package/lib/checks/managedWithoutKeys.js +3 -1
  25. package/lib/checks/selectItems.js +4 -4
  26. package/lib/checks/sql-snippets.js +27 -26
  27. package/lib/checks/types.js +1 -1
  28. package/lib/checks/validator.js +6 -11
  29. package/lib/compiler/assert-consistency.js +6 -3
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +19 -6
  32. package/lib/compiler/checks.js +23 -60
  33. package/lib/compiler/cycle-detector.js +1 -1
  34. package/lib/compiler/define.js +1151 -0
  35. package/lib/compiler/extend.js +1000 -0
  36. package/lib/compiler/finalize-parse-cdl.js +237 -0
  37. package/lib/compiler/index.js +107 -39
  38. package/lib/compiler/kick-start.js +190 -0
  39. package/lib/compiler/moduleLayers.js +4 -4
  40. package/lib/compiler/populate.js +1227 -0
  41. package/lib/compiler/propagator.js +114 -46
  42. package/lib/compiler/resolve.js +1521 -0
  43. package/lib/compiler/shared.js +126 -65
  44. package/lib/compiler/tweak-assocs.js +535 -0
  45. package/lib/compiler/utils.js +197 -33
  46. package/lib/edm/.eslintrc.json +5 -0
  47. package/lib/edm/annotations/genericTranslation.js +38 -24
  48. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  49. package/lib/edm/csn2edm.js +219 -100
  50. package/lib/edm/edm.js +302 -230
  51. package/lib/edm/edmPreprocessor.js +554 -419
  52. package/lib/edm/edmUtils.js +138 -44
  53. package/lib/gen/Dictionary.json +100 -19
  54. package/lib/gen/language.checksum +1 -1
  55. package/lib/gen/language.interp +11 -1
  56. package/lib/gen/language.tokens +86 -83
  57. package/lib/gen/languageLexer.interp +10 -1
  58. package/lib/gen/languageLexer.js +860 -833
  59. package/lib/gen/languageLexer.tokens +78 -75
  60. package/lib/gen/languageParser.js +5765 -4480
  61. package/lib/json/csnVersion.js +10 -11
  62. package/lib/json/from-csn.js +15 -3
  63. package/lib/json/to-csn.js +126 -68
  64. package/lib/language/docCommentParser.js +4 -4
  65. package/lib/language/genericAntlrParser.js +123 -5
  66. package/lib/language/language.g4 +355 -156
  67. package/lib/language/multiLineStringParser.js +5 -5
  68. package/lib/main.d.ts +486 -59
  69. package/lib/main.js +41 -9
  70. package/lib/model/api.js +3 -1
  71. package/lib/model/csnRefs.js +252 -156
  72. package/lib/model/csnUtils.js +384 -297
  73. package/lib/model/enrichCsn.js +71 -29
  74. package/lib/model/revealInternalProperties.js +29 -8
  75. package/lib/model/sortViews.js +2 -1
  76. package/lib/modelCompare/compare.js +23 -18
  77. package/lib/optionProcessor.js +63 -26
  78. package/lib/render/manageConstraints.js +35 -32
  79. package/lib/render/toCdl.js +897 -947
  80. package/lib/render/toHdbcds.js +205 -257
  81. package/lib/render/toSql.js +264 -225
  82. package/lib/render/utils/common.js +136 -25
  83. package/lib/render/utils/sql.js +4 -3
  84. package/lib/render/utils/stringEscapes.js +111 -0
  85. package/lib/sql-identifier.js +1 -1
  86. package/lib/transform/.eslintrc.json +5 -0
  87. package/lib/transform/db/.eslintrc.json +3 -1
  88. package/lib/transform/db/applyTransformations.js +35 -12
  89. package/lib/transform/db/assertUnique.js +1 -1
  90. package/lib/transform/db/associations.js +104 -306
  91. package/lib/transform/db/cdsPersistence.js +2 -2
  92. package/lib/transform/db/constraints.js +58 -53
  93. package/lib/transform/db/expansion.js +60 -33
  94. package/lib/transform/db/flattening.js +582 -104
  95. package/lib/transform/db/groupByOrderBy.js +3 -1
  96. package/lib/transform/db/transformExists.js +66 -13
  97. package/lib/transform/db/views.js +11 -7
  98. package/lib/transform/draft/.eslintrc.json +38 -0
  99. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  100. package/lib/transform/draft/odata.js +227 -0
  101. package/lib/transform/forHanaNew.js +109 -208
  102. package/lib/transform/forOdataNew.js +59 -212
  103. package/lib/transform/localized.js +46 -26
  104. package/lib/transform/odata/toFinalBaseType.js +85 -11
  105. package/lib/transform/odata/typesExposure.js +147 -199
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +44 -33
  108. package/lib/transform/translateAssocsToJoins.js +3 -20
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +172 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/moduleResolve.js +13 -6
  114. package/lib/utils/objectUtils.js +30 -0
  115. package/package.json +1 -1
  116. package/share/messages/README.md +26 -0
  117. package/share/messages/message-explanations.json +2 -1
  118. package/share/messages/syntax-expected-integer.md +37 -0
  119. package/lib/compiler/definer.js +0 -2361
  120. package/lib/compiler/resolver.js +0 -3079
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -290
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
  128. 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
- ## Added `noScopedRedirections`
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
- ## Added `noInheritedAutoexposeViaComposition`
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
- ## Added `downgradableErrors`
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
- ## Added `shortAutoexposed`
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
- ## Added `longAutoexposed`
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
- ## Added `generatedEntityNameWithUnderscore`
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`
@@ -22,22 +22,27 @@ others might want to [skip the introduction](#design-principles).
22
22
 
23
23
  ## Table of Contents
24
24
 
25
- 1. [Introduction](#introduction)
26
- <br/>  –  [Background: SQL](#background-sql)
27
- <br/>  –  [Background: modern programming languages](#background-modern-programming-languages)
28
- 2. [Design Principles](#design-principles)
29
- 3. [Name Resolution - the Basics](#name-resolution---the-basics)
30
- <br/>  –  [Common rules](#common-rules)
31
- <br/>  –  [Resolving paths](#resolving-paths)
32
- <br/>  –  [Navigation environment](#navigation-environment)
33
- 4. [References to main artifacts](#references-to-main-artifacts)
34
- 5. [Values and references to elements](#values-and-references-to-elements)
35
- <br/>  –  [References in queries](#references-in-queries)
36
- <br/>  –  [References to sibling elements](#references-to-sibling-elements)
37
- <br/>  –  [Other element references](#other-element-references)
38
- 6. [Paths as Annotation Values](#paths-as-annotation-values)
39
- 7. [Differences to HANA-CDS](#differences-to-hana-cds)
40
- 8. [Summary](#summary)
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 { cloneCsn } = require('../model/csnUtils');
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, throwWithError } = makeMessageFunction(csn, options, module);
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
- throwWithError();
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(cloneCsn(csn, internalOptions), internalOptions);
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 {hdiOptions} [options={}] Options
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 {hdbcdsOptions} [options={}] Options
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 {hdiOptions} [options={}] Options
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 sqlsWithCSNNamesToSort = Object.create(null);
251
- const sqlsNotToSort = Object.create(null);
252
+ const sqlArtifactsWithCSNNamesToSort = Object.create(null);
253
+ const sqlArtifactsNotToSort = Object.create(null);
252
254
 
253
- Object.keys(flat).forEach((key) => {
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
- sqlsWithCSNNamesToSort[artifactNameLikeInCsn] = flat[key];
259
+ sqlArtifactsWithCSNNamesToSort[artifactNameLikeInCsn] = flat[key];
258
260
  else
259
- sqlsNotToSort[key] = flat[key];
261
+ sqlArtifactsNotToSort[key] = flat[key];
260
262
  });
261
263
 
262
- const sorted = sortViews({ sql: sqlsWithCSNNamesToSort, csn: sqlCSN })
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 indizes
271
- Object.keys(sqlsNotToSort).forEach((key) => {
272
- sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlsNotToSort[key];
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
- for (const [ key, value ] of Object.entries(dict)) {
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 {hdiOptions} options Options
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 {hdiOptions|CSN.Model} inputOptions Options or CSN image
350
- * @param {CSN.Model|hdiOptions} inputBeforeImage CSN image or options
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
- for (const [ kind, artifacts ] of Object.entries(hdbkinds)) {
400
+ forEach(hdbkinds, (kind, artifacts) => {
399
401
  const suffix = `.${ kind }`;
400
- for (const [ name, sqlStatement ] of Object.entries(artifacts)) {
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
- for (const [ name ] of Object.entries(deletions))
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
- for (const [ name, changeset ] of Object.entries(migrations))
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 {hdbcdsOptions} [options={}] Options
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
- for (const [ fileType, artifacts ] of Object.entries(toProcess)) {
586
+ forEach(toProcess, (fileType, artifacts) => {
589
587
  if (fileType === 'messages')
590
- continue;
591
- for (const filename of Object.keys(artifacts))
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
- // options.testMode && err instanceof RangeError) // stack overflow
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/view...>:<content> }.
727
+ * A map of { <file.hdbtable|hdbview|hdbconstraint...>:<content> }.
765
728
  *
766
729
  * @typedef {object} HDIArtifacts
767
730
  */
@@ -49,7 +49,7 @@ const privateOptions = [
49
49
  'traceParserAmb',
50
50
  'testMode',
51
51
  'testSortCsn',
52
- 'constraintsAsAlter',
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]) && inputOptionNames.includes(name))
86
+ if (Array.isArray(input[name]))
88
87
  options[name] = [ ...input[name] ];
89
- else if (inputOptionNames.includes(name))
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', 'constraints-as-alter-sqlite' ], 'to.sql');
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', constraintsAsAlter: false };
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
 
@@ -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, throwWithError } = makeMessageFunction(null, messageCollector, moduleName);
163
+ const { error, throwWithAnyError } = makeMessageFunction(null, messageCollector, moduleName);
168
164
 
169
- for (const optionName of Object.keys(options)) {
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
- throwWithError();
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.throwWithError();
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(['quoted', 'hdbcds'].includes(options.toSql.names)) {
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(options) {
299
+ function transformUserOption(userOptions) {
300
300
  // move the user option value under user.id if specified as a string
301
- if (options.user && typeof options.user === 'string' || options.user instanceof String) {
302
- options.user = { id: options.user };
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 (options.locale) {
306
- options.user = options.user
307
- ? Object.assign(options.user, { locale: options.locale })
308
- : { locale: options.locale };
309
- delete options.locale;
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(['context', 'service'].includes(artifact.kind) && forHanaCsn.definitions[artifactName] === undefined) {
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
- if(options.testMode !== true)
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 -----------
@@ -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
+ };