@sap/cds-compiler 2.11.2 → 2.13.6

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 (140) hide show
  1. package/CHANGELOG.md +175 -2
  2. package/bin/.eslintrc.json +1 -2
  3. package/bin/cds_update_identifiers.js +10 -8
  4. package/bin/cdsc.js +23 -17
  5. package/bin/cdsse.js +2 -2
  6. package/bin/cdsv2m.js +3 -2
  7. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  8. package/doc/CHANGELOG_BETA.md +25 -6
  9. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  10. package/doc/NameResolution.md +21 -16
  11. package/lib/api/main.js +32 -79
  12. package/lib/api/options.js +3 -2
  13. package/lib/api/validate.js +2 -1
  14. package/lib/backends.js +16 -26
  15. package/lib/base/dictionaries.js +0 -8
  16. package/lib/base/error.js +26 -0
  17. package/lib/base/keywords.js +10 -19
  18. package/lib/base/location.js +9 -4
  19. package/lib/base/message-registry.js +75 -9
  20. package/lib/base/messages.js +31 -35
  21. package/lib/base/model.js +2 -62
  22. package/lib/base/optionProcessorHelper.js +246 -183
  23. package/lib/checks/.eslintrc.json +2 -0
  24. package/lib/checks/actionsFunctions.js +2 -1
  25. package/lib/checks/annotationsOData.js +1 -1
  26. package/lib/checks/cdsPersistence.js +2 -1
  27. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  28. package/lib/checks/enricher.js +17 -1
  29. package/lib/checks/foreignKeys.js +4 -4
  30. package/lib/checks/invalidTarget.js +3 -1
  31. package/lib/checks/managedInType.js +4 -4
  32. package/lib/checks/managedWithoutKeys.js +3 -1
  33. package/lib/checks/queryNoDbArtifacts.js +1 -3
  34. package/lib/checks/selectItems.js +4 -4
  35. package/lib/checks/sql-snippets.js +94 -0
  36. package/lib/checks/types.js +1 -1
  37. package/lib/checks/unknownMagic.js +1 -1
  38. package/lib/checks/validator.js +12 -7
  39. package/lib/compiler/assert-consistency.js +12 -8
  40. package/lib/compiler/base.js +0 -1
  41. package/lib/compiler/builtins.js +42 -21
  42. package/lib/compiler/checks.js +46 -12
  43. package/lib/compiler/cycle-detector.js +1 -1
  44. package/lib/compiler/define.js +1103 -0
  45. package/lib/compiler/extend.js +983 -0
  46. package/lib/compiler/finalize-parse-cdl.js +231 -0
  47. package/lib/compiler/index.js +46 -39
  48. package/lib/compiler/kick-start.js +190 -0
  49. package/lib/compiler/moduleLayers.js +4 -4
  50. package/lib/compiler/populate.js +1226 -0
  51. package/lib/compiler/propagator.js +113 -47
  52. package/lib/compiler/resolve.js +1433 -0
  53. package/lib/compiler/shared.js +100 -65
  54. package/lib/compiler/tweak-assocs.js +529 -0
  55. package/lib/compiler/utils.js +215 -33
  56. package/lib/edm/.eslintrc.json +5 -0
  57. package/lib/edm/annotations/genericTranslation.js +38 -25
  58. package/lib/edm/annotations/preprocessAnnotations.js +3 -3
  59. package/lib/edm/csn2edm.js +10 -9
  60. package/lib/edm/edm.js +19 -20
  61. package/lib/edm/edmPreprocessor.js +166 -95
  62. package/lib/edm/edmUtils.js +127 -34
  63. package/lib/gen/Dictionary.json +92 -43
  64. package/lib/gen/language.checksum +1 -1
  65. package/lib/gen/language.interp +11 -1
  66. package/lib/gen/language.tokens +86 -82
  67. package/lib/gen/languageLexer.interp +18 -1
  68. package/lib/gen/languageLexer.js +925 -847
  69. package/lib/gen/languageLexer.tokens +78 -74
  70. package/lib/gen/languageParser.js +5434 -4298
  71. package/lib/json/from-csn.js +59 -17
  72. package/lib/json/to-csn.js +189 -71
  73. package/lib/language/antlrParser.js +3 -3
  74. package/lib/language/docCommentParser.js +3 -3
  75. package/lib/language/errorStrategy.js +26 -8
  76. package/lib/language/genericAntlrParser.js +144 -53
  77. package/lib/language/language.g4 +424 -200
  78. package/lib/language/multiLineStringParser.js +536 -0
  79. package/lib/main.d.ts +550 -61
  80. package/lib/main.js +38 -11
  81. package/lib/model/api.js +3 -1
  82. package/lib/model/csnRefs.js +322 -198
  83. package/lib/model/csnUtils.js +226 -370
  84. package/lib/model/enrichCsn.js +124 -69
  85. package/lib/model/revealInternalProperties.js +29 -7
  86. package/lib/model/sortViews.js +10 -2
  87. package/lib/modelCompare/compare.js +17 -12
  88. package/lib/optionProcessor.js +8 -3
  89. package/lib/render/.eslintrc.json +1 -2
  90. package/lib/render/DuplicateChecker.js +1 -1
  91. package/lib/render/manageConstraints.js +36 -33
  92. package/lib/render/toCdl.js +174 -275
  93. package/lib/render/toHdbcds.js +203 -122
  94. package/lib/render/toRename.js +7 -10
  95. package/lib/render/toSql.js +161 -82
  96. package/lib/render/utils/common.js +22 -8
  97. package/lib/render/utils/sql.js +10 -7
  98. package/lib/render/utils/stringEscapes.js +111 -0
  99. package/lib/sql-identifier.js +1 -1
  100. package/lib/transform/.eslintrc.json +5 -0
  101. package/lib/transform/braceExpression.js +4 -2
  102. package/lib/transform/db/.eslintrc.json +2 -0
  103. package/lib/transform/db/applyTransformations.js +212 -0
  104. package/lib/transform/db/assertUnique.js +1 -1
  105. package/lib/transform/db/associations.js +187 -0
  106. package/lib/transform/db/cdsPersistence.js +150 -0
  107. package/lib/transform/db/constraints.js +61 -56
  108. package/lib/transform/db/expansion.js +50 -29
  109. package/lib/transform/db/flattening.js +556 -106
  110. package/lib/transform/db/groupByOrderBy.js +3 -1
  111. package/lib/transform/db/temporal.js +236 -0
  112. package/lib/transform/db/transformExists.js +103 -28
  113. package/lib/transform/db/views.js +92 -44
  114. package/lib/transform/draft/.eslintrc.json +38 -0
  115. package/lib/transform/{db/draft.js → draft/db.js} +9 -7
  116. package/lib/transform/draft/odata.js +227 -0
  117. package/lib/transform/forHanaNew.js +98 -783
  118. package/lib/transform/forOdataNew.js +22 -175
  119. package/lib/transform/localized.js +36 -32
  120. package/lib/transform/odata/generateForeignKeyElements.js +3 -3
  121. package/lib/transform/odata/referenceFlattener.js +95 -89
  122. package/lib/transform/odata/structureFlattener.js +1 -1
  123. package/lib/transform/odata/toFinalBaseType.js +86 -12
  124. package/lib/transform/odata/typesExposure.js +5 -5
  125. package/lib/transform/odata/utils.js +2 -2
  126. package/lib/transform/transformUtilsNew.js +47 -33
  127. package/lib/transform/translateAssocsToJoins.js +13 -30
  128. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  129. package/lib/transform/universalCsn/coreComputed.js +170 -0
  130. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  131. package/lib/transform/universalCsn/utils.js +63 -0
  132. package/lib/utils/file.js +8 -3
  133. package/lib/utils/objectUtils.js +30 -0
  134. package/lib/utils/timetrace.js +8 -2
  135. package/package.json +1 -1
  136. package/share/messages/README.md +26 -0
  137. package/lib/compiler/definer.js +0 -2349
  138. package/lib/compiler/resolver.js +0 -2922
  139. package/lib/transform/db/helpers.js +0 -58
  140. package/lib/transform/universalCsnEnricher.js +0 -67
package/lib/api/main.js CHANGED
@@ -35,6 +35,7 @@ const propertyToCheck = {
35
35
 
36
36
  const { cloneCsn } = require('../model/csnUtils');
37
37
  const { toHdbcdsSource } = require('../render/toHdbcds');
38
+ const { ModelError } = require('../base/error');
38
39
 
39
40
  const relevantGeneralOptions = [ /* for future generic options */ ];
40
41
  const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
@@ -115,7 +116,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
115
116
  * @returns {boolean} Return true if it is pre-transformed
116
117
  */
117
118
  function isPreTransformed(csn, transformation) {
118
- return csn.meta && csn.meta.transformation === transformation;
119
+ return csn && csn.meta && csn.meta.transformation === transformation;
119
120
  }
120
121
 
121
122
  /**
@@ -159,12 +160,13 @@ function cdl(csn, externalOptions = {}) {
159
160
  * Transform a CSN like to.sql
160
161
  *
161
162
  * @param {CSN.Model} csn Plain input CSN
162
- * @param {sqlOptions} [options={}] Options
163
+ * @param {SqlOptions} [options={}] Options
163
164
  * @returns {CSN.Model} CSN transformed like to.sql
164
165
  * @private
165
166
  */
166
167
  function forSql(csn, options = {}) {
167
168
  const internalOptions = prepareOptions.to.sql(options);
169
+ internalOptions.transformation = 'sql';
168
170
  internalOptions.toSql.csn = true;
169
171
  return backends.toSqlWithCsn(csn, internalOptions).csn;
170
172
  }
@@ -172,7 +174,7 @@ function forSql(csn, options = {}) {
172
174
  * Transform a CSN like to.hdi
173
175
  *
174
176
  * @param {CSN.Model} csn Plain input CSN
175
- * @param {hdiOptions} [options={}] Options
177
+ * @param {HdiOptions} [options={}] Options
176
178
  * @returns {CSN.Model} CSN transformed like to.hdi
177
179
  * @private
178
180
  */
@@ -185,7 +187,7 @@ function forHdi(csn, options = {}) {
185
187
  * Transform a CSN like to.hdbcds
186
188
  *
187
189
  * @param {CSN.Model} csn Plain input CSN
188
- * @param {hdbcdsOptions} [options={}] Options
190
+ * @param {HdbcdsOptions} [options={}] Options
189
191
  * @returns {CSN.Model} CSN transformed like to.hdbcds
190
192
  * @private
191
193
  */
@@ -202,11 +204,12 @@ function forHdbcds(csn, options = {}) {
202
204
  * Process the given CSN into SQL.
203
205
  *
204
206
  * @param {CSN.Model} csn A clean input CSN
205
- * @param {sqlOptions} [options={}] Options
207
+ * @param {SqlOptions} [options={}] Options
206
208
  * @returns {SQL[]} Array of SQL statements, tables first, views second
207
209
  */
208
210
  function sql(csn, options = {}) {
209
211
  const internalOptions = prepareOptions.to.sql(options);
212
+ internalOptions.transformation = 'sql';
210
213
 
211
214
  // we need the CSN for view sorting
212
215
  internalOptions.toSql.csn = true;
@@ -222,7 +225,7 @@ function sql(csn, options = {}) {
222
225
  * Process the given CSN into HDI artifacts.
223
226
  *
224
227
  * @param {CSN.Model} csn A clean input CSN
225
- * @param {hdiOptions} [options={}] Options
228
+ * @param {HdiOptions} [options={}] Options
226
229
  * @returns {HDIArtifacts} { <filename>:<content>, ...}
227
230
  */
228
231
  function hdi(csn, options = {}) {
@@ -245,19 +248,19 @@ function hdi(csn, options = {}) {
245
248
  const flat = flattenResultStructure(intermediateResult);
246
249
 
247
250
  const nameMapping = Object.create(null);
248
- const sqlsWithCSNNamesToSort = Object.create(null);
249
- const sqlsNotToSort = Object.create(null);
251
+ const sqlArtifactsWithCSNNamesToSort = Object.create(null);
252
+ const sqlArtifactsNotToSort = Object.create(null);
250
253
 
251
254
  Object.keys(flat).forEach((key) => {
252
255
  const artifactNameLikeInCsn = key.replace(/\.[^/.]+$/, '');
253
256
  nameMapping[artifactNameLikeInCsn] = key;
254
257
  if (key.endsWith('.hdbtable') || key.endsWith('.hdbview'))
255
- sqlsWithCSNNamesToSort[artifactNameLikeInCsn] = flat[key];
258
+ sqlArtifactsWithCSNNamesToSort[artifactNameLikeInCsn] = flat[key];
256
259
  else
257
- sqlsNotToSort[key] = flat[key];
260
+ sqlArtifactsNotToSort[key] = flat[key];
258
261
  });
259
262
 
260
- const sorted = sortViews({ sql: sqlsWithCSNNamesToSort, csn: sqlCSN })
263
+ const sorted = sortViews({ sql: sqlArtifactsWithCSNNamesToSort, csn: sqlCSN })
261
264
  .filter(obj => obj.sql)
262
265
  .reduce((previous, current) => {
263
266
  const hdiArtifactName = remapName(nameMapping[current.name], sqlCSN, k => !k.endsWith('.hdbindex'));
@@ -265,9 +268,9 @@ function hdi(csn, options = {}) {
265
268
  return previous;
266
269
  }, Object.create(null));
267
270
 
268
- // now add the not-sorted stuff, like indizes
269
- Object.keys(sqlsNotToSort).forEach((key) => {
270
- sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlsNotToSort[key];
271
+ // now add the not-sorted stuff, like indices
272
+ Object.keys(sqlArtifactsNotToSort).forEach((key) => {
273
+ sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlArtifactsNotToSort[key];
271
274
  });
272
275
 
273
276
  return sorted;
@@ -323,7 +326,7 @@ function remapName(key, csn, filter = () => true) {
323
326
  * Note: Only supports changes in entities (not views etc.) compiled/rendered as HANA-CSN/SQL.
324
327
  *
325
328
  * @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
326
- * @param {hdiOptions} options Options
329
+ * @param {HdiOptions} options Options
327
330
  * @param {CSN.Model} beforeImage A HANA-transformed CSN representing the "before-image", or null in case no such image
328
331
  * is known, i.e. for the very first migration step
329
332
  * @returns {object} - afterImage: The desired after-image in HANA-CSN format
@@ -344,8 +347,8 @@ function hdiMigration(csn, options, beforeImage) {
344
347
  * This is for backward compatibility with @sap/cds@4.5.(2…3).
345
348
  *
346
349
  * @todo Remove in cds-compiler@2.x
347
- * @param {hdiOptions|CSN.Model} inputOptions Options or CSN image
348
- * @param {CSN.Model|hdiOptions} inputBeforeImage CSN image or options
350
+ * @param {HdiOptions|CSN.Model} inputOptions Options or CSN image
351
+ * @param {HdiOptions|CSN.Model} inputBeforeImage CSN image or options
349
352
  * @returns {Array} Array where the real options come first
350
353
  */
351
354
  function backwardCompatible(inputOptions, inputBeforeImage) {
@@ -436,7 +439,7 @@ hdi.migration = hdiMigration;
436
439
  * Process the given CSN into HDBCDS artifacts.
437
440
  *
438
441
  * @param {any} csn A clean input CSN
439
- * @param {hdbcdsOptions} [options={}] Options
442
+ * @param {HdbcdsOptions} [options={}] Options
440
443
  * @returns {HDBCDS} { <filename>:<content>, ...}
441
444
  */
442
445
  function hdbcds(csn, options = {}) {
@@ -641,12 +644,18 @@ function publishCsnProcessor( processor, _name ) {
641
644
  return processor( csn, options, ...args );
642
645
  }
643
646
  catch (err) {
644
- if (err instanceof CompilationError || options.noRecompile)
645
- // options.testMode && err instanceof RangeError) // stack overflow
647
+ if (err instanceof CompilationError || options.noRecompile || isPreTransformed(csn, 'odata')) // we cannot recompile a pre-transformed CSN
648
+ throw err;
649
+
650
+ if (options.testMode && !(err instanceof TypeError) &&
651
+ !(err instanceof ModelError))
646
652
  throw err;
647
653
 
648
654
  const { info } = makeMessageFunction( csn, options, 'compile' );
649
- info( 'api-recompiled-csn', emptyLocation('csn.json'), {}, 'CSN input had to be recompiled' );
655
+ const msg = info( 'api-recompiled-csn', emptyLocation('csn.json'), {}, 'CSN input had to be recompiled' );
656
+ if (options.internalMsg)
657
+ msg.error = err; // Attach original error
658
+
650
659
  // next line to be replaced by CSN parser call which reads the CSN object
651
660
  const xsn = recompileX(csn, options);
652
661
  const recompiledCsn = compactModel(xsn);
@@ -680,12 +689,6 @@ function publishCsnProcessor( processor, _name ) {
680
689
  * @typedef {'plain' | 'quoted' | 'hdbcds' } NamingMode
681
690
  */
682
691
 
683
- /**
684
- * Available SQL change modes
685
- *
686
- * @typedef {'alter' | 'drop' } SqlChangeMode
687
- */
688
-
689
692
  /**
690
693
  * Available oData versions
691
694
  *
@@ -698,56 +701,6 @@ function publishCsnProcessor( processor, _name ) {
698
701
  * @typedef { 'structured' | 'flat' } oDataFormat
699
702
  */
700
703
 
701
- /**
702
- * Generally available options
703
- *
704
- * @typedef {object} Options
705
- * @property {object} [beta] Enable experimental features - not for productive use!
706
- * @property {boolean} [dependentAutoexposed=false] For dependent autoexposed entities (managed compositions, texts entity), follow name of base entity
707
- * @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
708
- * @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
709
- * @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
710
- */
711
-
712
- /**
713
- * Options available for to.hdi
714
- *
715
- * @typedef {object} hdiOptions
716
- * @property {NamingMode} [sqlMapping='plain'] Naming mode to use
717
- * @property {SqlChangeMode} [sqlChangeMode='alter'] SQL change mode to use (for changed columns)
718
- * @property {boolean} [allowCsnDowngrade=false] Allow downgrades of CSN major version (for modelCompare)
719
- * @property {object} [beta] Enable experimental features - not for productive use!
720
- * @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
721
- * @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
722
- * @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
723
- */
724
-
725
- /**
726
- * Options available for to.hdbcds
727
- *
728
- * @typedef {object} hdbcdsOptions
729
- * @property {NamingMode} [sqlMapping='plain'] Naming mode to use
730
- * @property {object} [beta] Enable experimental features - not for productive use!
731
- * @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
732
- * @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
733
- * @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
734
- */
735
-
736
- /**
737
- * Options available for to.sql
738
- *
739
- * @typedef {object} sqlOptions
740
- * @property {NamingMode} [sqlMapping='plain'] Naming mode to use
741
- * @property {SQLDialect} [sqlDialect='sqlite'] SQL dialect to use
742
- * @property {object} [variableReplacements] Object containing values for magic variables like "$user"
743
- * @property {string} [variableReplacements.$user.locale] Value for the "$user.locale" variable
744
- * @property {string} [variableReplacements.$user.id] Value for the "$userid" variable
745
- * @property {object} [beta] Enable experimental features - not for productive use!
746
- * @property {boolean} [longAutoexposed=false] Deprecated: Produce long names (with underscores) for autoexposed entities
747
- * @property {Map<string, number>} [severities={}] Map of message-id and severity that allows setting the severity for the given message
748
- * @property {Array} [messages] Allows collecting all messages in the options instead of printing them to stderr.
749
- */
750
-
751
704
  /**
752
705
  * A fresh (just compiled, not transformed) CSN
753
706
  *
@@ -767,13 +720,13 @@ function publishCsnProcessor( processor, _name ) {
767
720
  */
768
721
 
769
722
  /**
770
- * A map of { <file.hdbcds>:<content> }.
723
+ * A map of { <file.hdbcds|hdbconstraint>:<content> }.
771
724
  *
772
725
  * @typedef {object} HDBCDS
773
726
  */
774
727
 
775
728
  /**
776
- * A map of { <file.hdbtable/view...>:<content> }.
729
+ * A map of { <file.hdbtable|hdbview|hdbconstraint...>:<content> }.
777
730
  *
778
731
  * @typedef {object} HDIArtifacts
779
732
  */
@@ -49,6 +49,7 @@ const privateOptions = [
49
49
  'traceParserAmb',
50
50
  'testMode',
51
51
  'testSortCsn',
52
+ 'constraintsInCreateTable',
52
53
  'integrityNotEnforced',
53
54
  'integrityNotValidated',
54
55
  'assertIntegrity',
@@ -83,9 +84,9 @@ function translateOptions(input = {}, defaults = {}, hardRequire = {},
83
84
  for (const name of overallOptions) {
84
85
  // Ensure that arrays are not passed as a reference!
85
86
  // This caused issues with the way messages are handled in processMessages
86
- if (Array.isArray(input[name]) && inputOptionNames.indexOf(name) !== -1)
87
+ if (Array.isArray(input[name]) && inputOptionNames.includes(name))
87
88
  options[name] = [ ...input[name] ];
88
- else if (inputOptionNames.indexOf(name) !== -1)
89
+ else if (inputOptionNames.includes(name))
89
90
  options[name] = input[name];
90
91
  }
91
92
 
@@ -25,13 +25,14 @@ const booleanValidator = {
25
25
  /**
26
26
  * Generate a Validator that validates that the
27
27
  * input is a string and one of the available options.
28
+ * The validation of the option values is case-insensitive.
28
29
  *
29
30
  * @param {any} availableValues Available values
30
31
  * @returns {Validator} Return a validator for a string in an expected range
31
32
  */
32
33
  function generateStringValidator(availableValues) {
33
34
  return {
34
- validate: val => typeof val === 'string' && availableValues.indexOf(val) !== -1,
35
+ validate: val => typeof val === 'string' && availableValues.some( av => av.toLowerCase() === val.toLowerCase() ),
35
36
  expected: (val) => {
36
37
  return typeof val !== 'string' ? 'type string' : availableValues.join(', ');
37
38
  },
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
307
- ? Object.assign(options.user, { locale: options.locale })
308
- : options.user = { 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,18 +389,16 @@ 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
  });
396
396
 
397
397
  // Assemble result
398
- let result = {
398
+ return {
399
399
  rename : toRenameDdl(forHanaCsn, options),
400
400
  options
401
401
  };
402
-
403
- return result;
404
402
  }
405
403
 
406
404
  function alterConstraintsWithCsn(csn, options) {
@@ -418,6 +416,10 @@ function alterConstraintsWithCsn(csn, options) {
418
416
  names: names || 'plain'
419
417
  }
420
418
 
419
+ // Also set new-style options
420
+ options.sqlDialect = 'hana';
421
+ options.sqlMapping = names || 'plain';
422
+
421
423
  // Of course we want the database constraints
422
424
  options.assertIntegrityType = 'DB';
423
425
 
@@ -434,19 +436,7 @@ function alterConstraintsWithCsn(csn, options) {
434
436
  else
435
437
  intermediateResult = manageConstraints(forSqlCsn, mergedOptions);
436
438
 
437
- if(options.testMode !== true)
438
- return intermediateResult;
439
-
440
- // if in testmode, return a string containing all the artifacts
441
- let resultString = '';
442
- const extension = src && src === 'hdi' ? 'hdbconstraint' : 'sql';
443
- for(const id in intermediateResult){
444
- const initialComment = `--$ --- ${id}.${extension} ---\n\n`;
445
- resultString += initialComment;
446
- resultString += intermediateResult[id];
447
- resultString += '\n\n'
448
- }
449
- return resultString;
439
+ return intermediateResult;
450
440
  }
451
441
 
452
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
+ };
@@ -1,3 +1,7 @@
1
+ 'use strict';
2
+
3
+ const { functionsWithoutParens } = require("../compiler/builtins");
4
+
1
5
  module.exports = {
2
6
  // CDL reserved keywords, used for automatic quoting in 'toCdl' renderer
3
7
  // Keep in sync with reserved keywords in language.g4
@@ -11,7 +15,7 @@ module.exports = {
11
15
  'DISTINCT',
12
16
  'EXISTS',
13
17
  'EXTRACT',
14
- 'FALSE',
18
+ 'FALSE', // boolean
15
19
  'FROM',
16
20
  'IN',
17
21
  'KEY',
@@ -22,28 +26,15 @@ module.exports = {
22
26
  'ON',
23
27
  'SELECT',
24
28
  'SOME',
29
+ 'WHEN',
25
30
  'TRIM',
26
- 'TRUE',
31
+ 'TRUE', // boolean
27
32
  'WHERE',
28
33
  'WITH',
29
34
  ],
30
35
  // CDL functions, used for automatic quoting in 'toCdl' renderer,
31
36
  // only relevant for element references of path length 1.
32
- cdl_functions: [
33
- 'CURRENT_CONNECTION',
34
- 'CURRENT_DATE',
35
- 'CURRENT_SCHEMA',
36
- 'CURRENT_TIME',
37
- 'CURRENT_TIMESTAMP',
38
- 'CURRENT_TRANSACTION_ISOLATION_LEVEL',
39
- 'CURRENT_USER',
40
- 'CURRENT_UTCDATE',
41
- 'CURRENT_UTCTIME',
42
- 'CURRENT_UTCTIMESTAMP',
43
- 'SESSION_USER',
44
- 'SYSTEM_USER',
45
- 'SYSUUID',
46
- ],
37
+ cdl_functions: functionsWithoutParens,
47
38
  // SQLite keywords, used to warn in 'toSql' renderer with dialect 'sqlite'
48
39
  // Taken from http://www.sqlite.org/draft/lang_keywords.html
49
40
  // Better use keywords in tool/mkkeywordhash.c of a sqlite distribution.
@@ -194,7 +185,7 @@ module.exports = {
194
185
  'OTHERS',
195
186
  'TIES',
196
187
  ],
197
- // HANA keywords, used for smart quoting in to-hdi.plain
188
+ // SAP HANA keywords, used for smart quoting in to-hdi.plain
198
189
  // Taken from https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/28bcd6af3eb6437892719f7c27a8a285.html
199
190
  // Better use keywords in ptime/query/parser/syntax/qp_keyword.cc minus those
200
191
  // in rule unreserved_keyword_column (=…_common - "CONSTRAINT") in
@@ -674,7 +665,7 @@ module.exports = {
674
665
  'XMLTABLE',
675
666
  'YEAR'
676
667
  ],
677
- // HANA CDS keywords, used for smart quoting in to-hdbcds.plain
668
+ // SAP HANA CDS keywords, used for smart quoting in to-hdbcds.plain
678
669
  hdbcds: [
679
670
  'ALL', 'ALTER', 'AS',
680
671
  'BEFORE', 'BEGIN', 'BOTH',
@@ -12,6 +12,9 @@ const { copyPropIfExist } = require('../utils/objectUtils');
12
12
  * @param {XSN.WithLocation} start
13
13
  * @param {XSN.WithLocation} end
14
14
  * @returns {CSN.Location}
15
+ *
16
+ * TODO: make this function a CDL parser-only function (i.e. there should be
17
+ * no need to use it outside), it is XSN-only anyway already now
15
18
  */
16
19
  function combinedLocation( start, end ) {
17
20
  if (!start || !start.location)
@@ -33,6 +36,8 @@ function combinedLocation( start, end ) {
33
36
  *
34
37
  * @param {string} filename
35
38
  * @returns {CSN.Location}
39
+ *
40
+ * TODO: make this function redundant (XSN sparse locations project)
36
41
  */
37
42
  function emptyLocation(filename) {
38
43
  return {
@@ -50,6 +55,8 @@ function emptyLocation(filename) {
50
55
  *
51
56
  * @param {string} filename
52
57
  * @returns {CSN.Location}
58
+ *
59
+ * TODO: make this function redundant (XSN sparse locations project)
53
60
  */
54
61
  function emptyWeakLocation(filename) {
55
62
  return {
@@ -63,6 +70,8 @@ function emptyWeakLocation(filename) {
63
70
  * Returns a dummy location for built-in definitions.
64
71
  *
65
72
  * @returns {CSN.Location}
73
+ *
74
+ * TODO: make this function redundant (XSN sparse locations project)
66
75
  */
67
76
  function builtinLocation() {
68
77
  return emptyLocation('<built-in>');
@@ -140,10 +149,6 @@ function dictLocation( dict, extraLocation ) {
140
149
  endCol: max.endCol,
141
150
  };
142
151
  }
143
- dictLocation.end = (dict) => {
144
- const loc = dictLocation( dict );
145
- return loc && { file: loc.file, line: loc.endLine, col: loc.endCol };
146
- };
147
152
 
148
153
  function _objLocations( obj ) {
149
154
  return Array.isArray(obj) ? obj.map( o => o.location ) : [ obj.location ];