@sap/cds-compiler 3.4.2 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +15 -16
  5. package/bin/cdshi.js +19 -6
  6. package/doc/CHANGELOG_ARCHIVE.md +2 -2
  7. package/doc/CHANGELOG_BETA.md +9 -1
  8. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  9. package/lib/api/main.js +61 -59
  10. package/lib/api/options.js +4 -2
  11. package/lib/api/validate.js +2 -2
  12. package/lib/base/cleanSymbols.js +2 -3
  13. package/lib/base/dictionaries.js +6 -6
  14. package/lib/base/error.js +2 -2
  15. package/lib/base/keywords.js +6 -6
  16. package/lib/base/location.js +11 -12
  17. package/lib/base/message-registry.js +177 -58
  18. package/lib/base/messages.js +252 -180
  19. package/lib/base/model.js +14 -11
  20. package/lib/base/node-helpers.js +9 -10
  21. package/lib/base/optionProcessorHelper.js +138 -129
  22. package/lib/checks/.eslintrc.json +2 -0
  23. package/lib/checks/actionsFunctions.js +5 -5
  24. package/lib/checks/annotationsOData.js +4 -4
  25. package/lib/checks/arrayOfs.js +1 -1
  26. package/lib/checks/cdsPersistence.js +1 -1
  27. package/lib/checks/checkForTypes.js +3 -3
  28. package/lib/checks/defaultValues.js +3 -3
  29. package/lib/checks/elements.js +7 -7
  30. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  31. package/lib/checks/foreignKeys.js +1 -1
  32. package/lib/checks/invalidTarget.js +4 -4
  33. package/lib/checks/managedInType.js +1 -1
  34. package/lib/checks/managedWithoutKeys.js +1 -1
  35. package/lib/checks/nonexpandableStructured.js +5 -3
  36. package/lib/checks/nullableKeys.js +1 -1
  37. package/lib/checks/onConditions.js +5 -6
  38. package/lib/checks/parameters.js +1 -1
  39. package/lib/checks/queryNoDbArtifacts.js +2 -2
  40. package/lib/checks/selectItems.js +4 -4
  41. package/lib/checks/sql-snippets.js +4 -4
  42. package/lib/checks/types.js +7 -7
  43. package/lib/checks/utils.js +4 -4
  44. package/lib/checks/validator.js +16 -13
  45. package/lib/compiler/.eslintrc.json +4 -1
  46. package/lib/compiler/assert-consistency.js +8 -7
  47. package/lib/compiler/builtins.js +14 -14
  48. package/lib/compiler/checks.js +123 -48
  49. package/lib/compiler/define.js +12 -13
  50. package/lib/compiler/extend.js +266 -60
  51. package/lib/compiler/finalize-parse-cdl.js +10 -5
  52. package/lib/compiler/index.js +17 -14
  53. package/lib/compiler/populate.js +14 -6
  54. package/lib/compiler/propagator.js +2 -0
  55. package/lib/compiler/resolve.js +2 -15
  56. package/lib/compiler/shared.js +27 -16
  57. package/lib/compiler/tweak-assocs.js +5 -6
  58. package/lib/compiler/utils.js +20 -0
  59. package/lib/edm/annotations/genericTranslation.js +604 -358
  60. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  61. package/lib/edm/csn2edm.js +275 -222
  62. package/lib/edm/edm.js +17 -3
  63. package/lib/edm/edmAnnoPreprocessor.js +6 -6
  64. package/lib/edm/edmInboundChecks.js +2 -2
  65. package/lib/edm/edmPreprocessor.js +107 -77
  66. package/lib/edm/edmUtils.js +44 -5
  67. package/lib/gen/Dictionary.json +210 -8
  68. package/lib/gen/language.checksum +1 -1
  69. package/lib/gen/language.interp +67 -63
  70. package/lib/gen/language.tokens +81 -81
  71. package/lib/gen/languageLexer.interp +4 -10
  72. package/lib/gen/languageLexer.js +854 -869
  73. package/lib/gen/languageLexer.tokens +79 -81
  74. package/lib/gen/languageParser.js +14309 -13832
  75. package/lib/inspect/inspectModelStatistics.js +2 -2
  76. package/lib/inspect/inspectPropagation.js +6 -6
  77. package/lib/inspect/inspectUtils.js +2 -2
  78. package/lib/json/from-csn.js +102 -55
  79. package/lib/json/to-csn.js +119 -198
  80. package/lib/language/antlrParser.js +5 -2
  81. package/lib/language/docCommentParser.js +6 -6
  82. package/lib/language/errorStrategy.js +43 -23
  83. package/lib/language/genericAntlrParser.js +113 -133
  84. package/lib/language/language.g4 +1550 -1506
  85. package/lib/language/multiLineStringParser.js +3 -3
  86. package/lib/language/textUtils.js +2 -2
  87. package/lib/main.js +3 -3
  88. package/lib/model/csnRefs.js +5 -0
  89. package/lib/model/csnUtils.js +130 -122
  90. package/lib/model/revealInternalProperties.js +1 -1
  91. package/lib/model/sortViews.js +4 -6
  92. package/lib/modelCompare/compare.js +2 -2
  93. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  94. package/lib/modelCompare/utils/filter.js +100 -0
  95. package/lib/optionProcessor.js +5 -0
  96. package/lib/render/.eslintrc.json +1 -0
  97. package/lib/render/DuplicateChecker.js +1 -1
  98. package/lib/render/manageConstraints.js +12 -12
  99. package/lib/render/toCdl.js +311 -276
  100. package/lib/render/toHdbcds.js +97 -94
  101. package/lib/render/toRename.js +5 -5
  102. package/lib/render/toSql.js +127 -223
  103. package/lib/render/utils/common.js +141 -108
  104. package/lib/render/utils/delta.js +227 -0
  105. package/lib/render/utils/sql.js +22 -6
  106. package/lib/render/utils/stringEscapes.js +3 -3
  107. package/lib/transform/db/.eslintrc.json +2 -0
  108. package/lib/transform/db/applyTransformations.js +3 -3
  109. package/lib/transform/db/assertUnique.js +13 -12
  110. package/lib/transform/db/associations.js +5 -5
  111. package/lib/transform/db/cdsPersistence.js +10 -8
  112. package/lib/transform/db/constraints.js +14 -14
  113. package/lib/transform/db/expansion.js +20 -22
  114. package/lib/transform/db/flattening.js +24 -42
  115. package/lib/transform/db/groupByOrderBy.js +3 -3
  116. package/lib/transform/db/temporal.js +6 -6
  117. package/lib/transform/db/transformExists.js +23 -23
  118. package/lib/transform/db/views.js +16 -16
  119. package/lib/transform/draft/.eslintrc.json +1 -35
  120. package/lib/transform/draft/db.js +10 -10
  121. package/lib/transform/draft/odata.js +2 -2
  122. package/lib/transform/forOdataNew.js +8 -29
  123. package/lib/transform/forRelationalDB.js +16 -6
  124. package/lib/transform/localized.js +11 -10
  125. package/lib/transform/odata/toFinalBaseType.js +41 -27
  126. package/lib/transform/odata/typesExposure.js +113 -47
  127. package/lib/transform/parseExpr.js +209 -106
  128. package/lib/transform/transformUtilsNew.js +17 -10
  129. package/lib/transform/translateAssocsToJoins.js +24 -19
  130. package/lib/transform/universalCsn/coreComputed.js +10 -10
  131. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  132. package/lib/transform/universalCsn/utils.js +3 -3
  133. package/lib/utils/file.js +5 -5
  134. package/lib/utils/moduleResolve.js +13 -13
  135. package/lib/utils/objectUtils.js +6 -6
  136. package/lib/utils/term.js +5 -2
  137. package/lib/utils/timetrace.js +51 -24
  138. package/package.json +5 -8
  139. package/share/messages/check-proper-type-of.md +1 -1
  140. package/share/messages/message-explanations.json +1 -1
  141. package/share/messages/redirected-to-complex.md +4 -4
  142. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
  143. package/lib/modelCompare/filter.js +0 -83
@@ -7,9 +7,9 @@ const {
7
7
  } = require('../model/csnUtils');
8
8
  const keywords = require('../base/keywords');
9
9
  const {
10
- renderFunc, getExpressionRenderer, getRealName, addContextMarkers, addIntermediateContexts,
10
+ renderFunc, createExpressionRenderer, getRealName, addContextMarkers, addIntermediateContexts,
11
11
  hasHanaComment, getHanaComment, funcWithoutParen, getSqlSnippets,
12
- cdsToSqlTypes, cdsToHdbcdsTypes,
12
+ cdsToSqlTypes, cdsToHdbcdsTypes, withoutCast,
13
13
  } = require('./utils/common');
14
14
  const {
15
15
  renderReferentialConstraint,
@@ -32,7 +32,7 @@ const $SELF = '$self';
32
32
  * @param {CSN.Artifact} obj
33
33
  * @returns {string}
34
34
  */
35
- function getEscapedHanaComment(obj) {
35
+ function getEscapedHanaComment( obj ) {
36
36
  return getHanaComment(obj).replace(/\n/g, '\\n').replace(/'/g, "''");
37
37
  }
38
38
 
@@ -42,7 +42,7 @@ function getEscapedHanaComment(obj) {
42
42
  * @param {string} str
43
43
  * @returns {string}
44
44
  */
45
- function renderStringForHdbcds(str) {
45
+ function renderStringForHdbcds( str ) {
46
46
  return `'${str.replace(/'/g, '\'\'')}'`;
47
47
  }
48
48
 
@@ -60,7 +60,7 @@ function renderStringForHdbcds(str) {
60
60
  * @param {CSN.Options} [options] Transformation options
61
61
  * @returns {object} Dictionary of filename: content
62
62
  */
63
- function toHdbcdsSource(csn, options) {
63
+ function toHdbcdsSource( csn, options ) {
64
64
  timetrace.start('HDBCDS rendering');
65
65
  const plainNames = options.sqlMapping === 'plain';
66
66
  const quotedNames = options.sqlMapping === 'quoted';
@@ -70,37 +70,41 @@ function toHdbcdsSource(csn, options) {
70
70
  info, warning, error, throwWithAnyError,
71
71
  } = makeMessageFunction(csn, options, 'to.hdbcds');
72
72
 
73
- const renderExpr = getExpressionRenderer({
73
+ const exprRenderer = createExpressionRenderer({
74
74
  finalize: x => x,
75
- explicitTypeCast(x, env) {
76
- let typeRef = renderTypeReference(x.cast, env);
77
-
75
+ typeCast(x) {
76
+ let typeRef = renderTypeReference(x.cast, this.env);
78
77
  // inside a cast expression, the cds and hana cds types need to be mapped to hana sql types
79
78
  const hanaSqlType = cdsToSqlTypes.hana[x.cast.type] || cdsToSqlTypes.standard[x.cast.type];
80
79
  if (hanaSqlType) {
81
80
  const typeRefWithoutParams = typeRef.substring(0, typeRef.indexOf('(')) || typeRef;
82
81
  typeRef = typeRef.replace(typeRefWithoutParams, hanaSqlType);
83
82
  }
84
- return `CAST(${renderExpr(x, env)} AS ${typeRef})`;
83
+ return `CAST(${this.renderExpr(withoutCast(x))} AS ${typeRef})`;
85
84
  },
86
85
  val: renderExpressionLiteral,
87
86
  enum: x => `#${x['#']}`,
88
87
  ref: renderExpressionRef,
89
- aliasOnly(x, _env) {
90
- return x.as;
91
- },
88
+ aliasOnly: x => x.as,
92
89
  windowFunction: renderExpressionFunc,
93
90
  func: renderExpressionFunc,
94
- xpr(x, env) {
95
- if (this.nestedExpr && !x.cast)
96
- return `(${renderExpr(x.xpr, env, this.inline, true)})`;
97
-
98
- return renderExpr(x.xpr, env, this.inline, true);
91
+ xpr(x) {
92
+ if (this.isNestedXpr && !x.cast)
93
+ return `(${this.renderSubExpr(x.xpr)})`;
94
+ return this.renderSubExpr(x.xpr);
95
+ },
96
+ SELECT(x) {
97
+ return `(${renderQuery(x, false, increaseIndent(this.env))})`;
98
+ },
99
+ SET(x) {
100
+ return `${renderQuery(x, false, increaseIndent(this.env))}`;
99
101
  },
100
- SELECT: (x, env) => `(${renderQuery(x, false, increaseIndent(env))})`,
101
- SET: (x, env) => `${renderQuery(x, false, increaseIndent(env))}`,
102
102
  });
103
103
 
104
+ function renderExpr( x, env ) {
105
+ return exprRenderer.renderExpr(x, env);
106
+ }
107
+
104
108
  checkCSNVersion(csn, options);
105
109
 
106
110
  const hdbcdsResult = Object.create(null);
@@ -160,7 +164,7 @@ function toHdbcdsSource(csn, options) {
160
164
  killList.forEach(fn => fn());
161
165
 
162
166
  throwWithAnyError();
163
- timetrace.stop();
167
+ timetrace.stop('HDBCDS rendering');
164
168
  return options.testMode ? sort(hdbcdsResult) : hdbcdsResult;
165
169
 
166
170
  /**
@@ -169,7 +173,7 @@ function toHdbcdsSource(csn, options) {
169
173
  * @param {Object} obj Object to sort
170
174
  * @returns {Object} With keys sorted
171
175
  */
172
- function sort(obj) {
176
+ function sort( obj ) {
173
177
  const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b));
174
178
  const sortedResult = Object.create(null);
175
179
  for (let i = 0; i < keys.length; i++)
@@ -186,7 +190,7 @@ function toHdbcdsSource(csn, options) {
186
190
  * @param {CdlRenderEnvironment} env Environment
187
191
  * @returns {string} The rendered artifact
188
192
  */
189
- function renderArtifact(artifactName, art, env) {
193
+ function renderArtifact( artifactName, art, env ) {
190
194
  // FIXME: Correctly build the paths during runtime to give better locations
191
195
  env.path = [ 'definitions', artifactName ];
192
196
  // Ignore whole artifacts if toHana says so
@@ -229,7 +233,7 @@ function toHdbcdsSource(csn, options) {
229
233
  * @param {string} artifactName Find all children of this artifact
230
234
  * @returns {object} Dictionary with direct sub-artifacts
231
235
  */
232
- function getSubArtifacts(artifactName) {
236
+ function getSubArtifacts( artifactName ) {
233
237
  const prefix = `${artifactName}.`;
234
238
  const result = Object.create(null);
235
239
  for (const name in csn.definitions) {
@@ -261,7 +265,7 @@ function toHdbcdsSource(csn, options) {
261
265
  * @param {string} contextName Name of the (grand?)parent context
262
266
  * @returns {boolean} True if there is another context in between
263
267
  */
264
- function isContainedInOtherContext(containee, contextName) {
268
+ function isContainedInOtherContext( containee, contextName ) {
265
269
  const parts = containee.split('.');
266
270
  const prefixLength = contextName.split('.').length;
267
271
 
@@ -329,7 +333,7 @@ function toHdbcdsSource(csn, options) {
329
333
  * @param {CdlRenderEnvironment} env Environment
330
334
  * @returns {string} The rendered context/service
331
335
  */
332
- function renderContext(artifactName, art, env, isShadowed) {
336
+ function renderContext( artifactName, art, env, isShadowed ) {
333
337
  let result = '';
334
338
  if (!isShadowed)
335
339
  isShadowed = contextIsShadowed(artifactName);
@@ -361,7 +365,7 @@ function toHdbcdsSource(csn, options) {
361
365
  * @param {string} artifactName
362
366
  * @returns {boolean}
363
367
  */
364
- function contextIsShadowed(artifactName) {
368
+ function contextIsShadowed( artifactName ) {
365
369
  if (artifactName.indexOf('.') === -1)
366
370
  return false;
367
371
 
@@ -383,7 +387,7 @@ function toHdbcdsSource(csn, options) {
383
387
  * @param {string} name Possibly dotted artifact name
384
388
  * @returns {CdlRenderEnvironment} Updated env or original instance
385
389
  */
386
- function updatePrefixForDottedName(env, name) {
390
+ function updatePrefixForDottedName( env, name ) {
387
391
  if (plainNames) {
388
392
  let innerEnv = env;
389
393
  if (name.indexOf('.') !== -1) {
@@ -405,7 +409,7 @@ function toHdbcdsSource(csn, options) {
405
409
  * @param {CdlRenderEnvironment} env Environment
406
410
  * @returns {string} The rendered children of the namespace
407
411
  */
408
- function renderNamespace(artifactName, art, env) {
412
+ function renderNamespace( artifactName, art, env ) {
409
413
  // We currently do not render anything for a namespace, we just append its id to
410
414
  // the environment's current name prefix and descend into its children
411
415
  let result = '';
@@ -425,7 +429,7 @@ function toHdbcdsSource(csn, options) {
425
429
  * @param {CdlRenderEnvironment} env Environment
426
430
  * @returns {string} The rendered entity
427
431
  */
428
- function renderEntity(artifactName, art, env) {
432
+ function renderEntity( artifactName, art, env ) {
429
433
  let result = '';
430
434
  const childEnv = increaseIndent(env);
431
435
  const normalizedArtifactName = renderArtifactName(artifactName, env);
@@ -474,7 +478,7 @@ function toHdbcdsSource(csn, options) {
474
478
  * @param {CSN.Artifact} art
475
479
  * @param {CdlRenderEnvironment} env
476
480
  */
477
- function createTopLevelAliasesForArtifact(artName, art, env) {
481
+ function createTopLevelAliasesForArtifact( artName, art, env ) {
478
482
  forEachMember(art, (element) => {
479
483
  if (!element.target)
480
484
  return;
@@ -499,7 +503,7 @@ function toHdbcdsSource(csn, options) {
499
503
  * @param {CdlRenderEnvironment} env Environment
500
504
  * @returns {string} Return the resulting source string.
501
505
  */
502
- function renderTechnicalConfiguration(tc, env) {
506
+ function renderTechnicalConfiguration( tc, env ) {
503
507
  let result = '';
504
508
  const childEnv = increaseIndent(env);
505
509
 
@@ -573,7 +577,7 @@ function toHdbcdsSource(csn, options) {
573
577
  * @param {string} columnName Name of the SQL column
574
578
  * @returns {Array} Modified expression array
575
579
  */
576
- function fixFuzzyIndex(fuzzyIndex, columnName) {
580
+ function fixFuzzyIndex( fuzzyIndex, columnName ) {
577
581
  return fuzzyIndex.map(token => (token === 'on' ? { xpr: [ 'on', '(', { ref: columnName.split('.') }, ')' ] } : token));
578
582
  }
579
583
  }
@@ -589,7 +593,7 @@ function toHdbcdsSource(csn, options) {
589
593
  * @param {boolean} [isSubElement] Whether the given element is a subelement or not - subelements cannot be key!
590
594
  * @returns {string} The rendered element
591
595
  */
592
- function renderElement(elementName, elm, env, duplicateChecker, isSubElement) {
596
+ function renderElement( elementName, elm, env, duplicateChecker, isSubElement ) {
593
597
  // Ignore if toHana says so
594
598
  if (elm.virtual)
595
599
  return '';
@@ -630,7 +634,7 @@ function toHdbcdsSource(csn, options) {
630
634
  * @param {CdlRenderEnvironment} env Environment
631
635
  * @returns {string} Rendered view source
632
636
  */
633
- function renderViewSource(source, env) {
637
+ function renderViewSource( source, env ) {
634
638
  // Sub-SELECT
635
639
  if (source.SELECT || source.SET) {
636
640
  let result = `(${renderQuery(source, false, increaseIndent(env))})`;
@@ -647,7 +651,7 @@ function toHdbcdsSource(csn, options) {
647
651
  result = `(${result} ${source.join} `;
648
652
  result += `join ${renderViewSource(source.args[i], env)}`;
649
653
  if (source.on)
650
- result += ` on ${renderExpr(source.on, env, true, true)}`;
654
+ result += ` on ${renderExpr(source.on, env)}`;
651
655
 
652
656
  result += ')';
653
657
  }
@@ -667,7 +671,7 @@ function toHdbcdsSource(csn, options) {
667
671
  * @param {CdlRenderEnvironment} env Environment
668
672
  * @returns {string} Rendered path
669
673
  */
670
- function renderAbsolutePath(path, env) {
674
+ function renderAbsolutePath( path, env ) {
671
675
  // Sanity checks
672
676
  if (!path.ref)
673
677
  throw new ModelError(`Expecting ref in path: ${JSON.stringify(path)}`);
@@ -688,7 +692,7 @@ function toHdbcdsSource(csn, options) {
688
692
  result += `(${renderArgs(path.ref[0], ':', env)})`;
689
693
 
690
694
  if (path.ref[0].where)
691
- result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env, true, true)}]`;
695
+ result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env)}]`;
692
696
 
693
697
  // Add any path steps (possibly with parameters and filters) that may follow after that
694
698
  if (path.ref.length > 1)
@@ -708,7 +712,7 @@ function toHdbcdsSource(csn, options) {
708
712
  * @param {CdlRenderEnvironment} env Environment
709
713
  * @returns {string} Rendered path including alias
710
714
  */
711
- function renderAbsolutePathWithAlias(path, env) {
715
+ function renderAbsolutePathWithAlias( path, env ) {
712
716
  let result = renderAbsolutePath(path, env);
713
717
  // Take care of aliases - for artifact references, use the resulting name (multi-dot joined with _)
714
718
  const implicitAlias = path.ref.length === 0 ? getLastPartOf(getResultingName(csn, options.sqlMapping, path.ref[0])) : getLastPartOfRef(path.ref);
@@ -733,7 +737,7 @@ function toHdbcdsSource(csn, options) {
733
737
  * @param {CdlRenderEnvironment} env Environment
734
738
  * @returns {string} Rendered column
735
739
  */
736
- function renderViewColumn(col, elements, env ) {
740
+ function renderViewColumn( col, elements, env ) {
737
741
  // Annotations and column
738
742
  let result = '';
739
743
 
@@ -761,7 +765,7 @@ function toHdbcdsSource(csn, options) {
761
765
  error(null, env.path, { tokensymbol: 'key', $reviewed: true }, 'Unexpected $(TOKENSYMBOL) in subquery');
762
766
 
763
767
  const key = (!env.skipKeys && (col.key || (element && element.key)) ? 'key ' : '');
764
- result += key + renderExpr(col, env, true);
768
+ result += key + renderExpr(withoutCast(col), env);
765
769
  let alias = col.as || col.func;
766
770
  // HANA requires an alias for 'key' columns just for syntactical reasons
767
771
  // FIXME: This will not complain for non-refs (but that should be checked in forRelationalDB)
@@ -779,7 +783,7 @@ function toHdbcdsSource(csn, options) {
779
783
  // Redirections are never flattened (don't exist in HANA)
780
784
  result += ` : redirected to ${renderAbsoluteNameWithQuotes(col.cast.target, env)}`;
781
785
  if (col.cast.on)
782
- result += ` on ${renderExpr(col.cast.on, env, true, true)}`;
786
+ result += ` on ${renderExpr(col.cast.on, env)}`;
783
787
  }
784
788
 
785
789
  return result;
@@ -796,7 +800,7 @@ function toHdbcdsSource(csn, options) {
796
800
  * @param {CdlRenderEnvironment} env Environment
797
801
  * @returns {string} The rendered view
798
802
  */
799
- function renderView(artifactName, art, env) {
803
+ function renderView( artifactName, art, env ) {
800
804
  let result = '';
801
805
  const artifactPath = [ 'definitions', artifactName ];
802
806
  globalDuplicateChecker.addArtifact(art['@cds.persistence.name'], artifactPath, artifactName);
@@ -840,7 +844,7 @@ function toHdbcdsSource(csn, options) {
840
844
  * @param {object} [elements] For leading query, the elements of the artifact
841
845
  * @returns {string} The rendered query
842
846
  */
843
- function renderQuery(query, isLeadingQuery, env, path = [], elements = null) {
847
+ function renderQuery( query, isLeadingQuery, env, path = [], elements = null ) {
844
848
  let result = '';
845
849
  env.skipKeys = !isLeadingQuery;
846
850
  // Set operator, like UNION, INTERSECT, ...
@@ -908,15 +912,15 @@ function toHdbcdsSource(csn, options) {
908
912
  * @param {CdlRenderEnvironment} env Environment
909
913
  * @returns {string} The query with WHERE etc. added
910
914
  */
911
- function renderSelectProperties(select, alreadyRendered, env) {
915
+ function renderSelectProperties( select, alreadyRendered, env ) {
912
916
  if (select.where)
913
- alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
917
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env)}`;
914
918
 
915
919
  if (select.groupBy)
916
- alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env, true, false, true)).join(', ')}`;
920
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env)).join(', ')}`;
917
921
 
918
922
  if (select.having)
919
- alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env, true, true)}`;
923
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env)}`;
920
924
 
921
925
  if (select.orderBy)
922
926
  alreadyRendered += `${continueIndent(alreadyRendered, env)}order by ${select.orderBy.map(entry => renderOrderByEntry(entry, env)).join(', ')}`;
@@ -934,7 +938,7 @@ function toHdbcdsSource(csn, options) {
934
938
  * @param {CdlRenderEnvironment} env Environment
935
939
  * @returns {string} String to join with
936
940
  */
937
- function continueIndent(result, env) {
941
+ function continueIndent( result, env ) {
938
942
  if (result.endsWith('}') || result.endsWith('})')) {
939
943
  // The preceding clause ended with '}', just append after that
940
944
  return ' ';
@@ -950,7 +954,7 @@ function toHdbcdsSource(csn, options) {
950
954
  * @param {CdlRenderEnvironment} env Environment
951
955
  * @returns {string} Rendered limit clause
952
956
  */
953
- function renderLimit(limit, env) {
957
+ function renderLimit( limit, env ) {
954
958
  let result = '';
955
959
  if (limit.rows !== undefined)
956
960
  result += `limit ${renderExpr(limit.rows, env)}`;
@@ -969,8 +973,8 @@ function toHdbcdsSource(csn, options) {
969
973
  * @param {CdlRenderEnvironment} env Environment
970
974
  * @returns {string} Rendered order by
971
975
  */
972
- function renderOrderByEntry(entry, env) {
973
- let result = renderExpr(entry, env, true, false, true);
976
+ function renderOrderByEntry( entry, env ) {
977
+ let result = renderExpr(entry, env);
974
978
  if (entry.sort)
975
979
  result += ` ${entry.sort}`;
976
980
 
@@ -988,7 +992,7 @@ function toHdbcdsSource(csn, options) {
988
992
  * @param {CdlRenderEnvironment} env Environment
989
993
  * @returns {string} The resulting parameter as source string (no trailing LF).
990
994
  */
991
- function renderParameter(parName, par, env) {
995
+ function renderParameter( parName, par, env ) {
992
996
  if (par.notNull === true || par.notNull === false)
993
997
  info('query-ignoring-param-nullability', env.path.concat([ 'params', parName ]), { '#': 'std' });
994
998
  return `${env.indent + formatParamIdentifier(parName, env.path.concat([ 'params', parName ]))} : ${renderTypeReference(par, env)}`;
@@ -1003,7 +1007,7 @@ function toHdbcdsSource(csn, options) {
1003
1007
  * @param {CdlRenderEnvironment} env Environment
1004
1008
  * @returns {string} Rendered type/annotation
1005
1009
  */
1006
- function renderType(artifactName, art, env) {
1010
+ function renderType( artifactName, art, env ) {
1007
1011
  if (art.kind === 'aspect' || art.kind === 'type' && !hdbcdsNames || art.kind === 'type' && hdbcdsNames && !art.elements)
1008
1012
  return '';
1009
1013
  let result = '';
@@ -1036,7 +1040,7 @@ function toHdbcdsSource(csn, options) {
1036
1040
  * @param {CdlRenderEnvironment} env Environment
1037
1041
  * @returns {string} Rendered type reference
1038
1042
  */
1039
- function renderTypeReference(elm, env) {
1043
+ function renderTypeReference( elm, env ) {
1040
1044
  let result = '';
1041
1045
 
1042
1046
  // Array type: Render items instead
@@ -1095,7 +1099,7 @@ function toHdbcdsSource(csn, options) {
1095
1099
  * @param {CdlRenderEnvironment} env
1096
1100
  * @returns {string}
1097
1101
  */
1098
- function renderAssociationType(elm, env) {
1102
+ function renderAssociationType( elm, env ) {
1099
1103
  // Type, cardinality and target
1100
1104
  let result = 'association';
1101
1105
 
@@ -1118,7 +1122,7 @@ function toHdbcdsSource(csn, options) {
1118
1122
 
1119
1123
  // ON-condition (if any)
1120
1124
  if (elm.on) {
1121
- result += ` on ${renderExpr(elm.on, env, true, true)}`;
1125
+ result += ` on ${renderExpr(elm.on, env)}`;
1122
1126
  }
1123
1127
  else if (elm.targetAspect && elm.targetAspect.elements) { // anonymous aspect
1124
1128
  const childEnv = increaseIndent(env);
@@ -1144,7 +1148,7 @@ function toHdbcdsSource(csn, options) {
1144
1148
  * @param {CSN.Element} elm Element with the type
1145
1149
  * @returns {string} The rendered type
1146
1150
  */
1147
- function renderBuiltinType(elm) {
1151
+ function renderBuiltinType( elm ) {
1148
1152
  if (elm.type === 'cds.Decimal' && elm.scale === undefined && elm.precision === undefined)
1149
1153
  return 'DecimalFloat';
1150
1154
 
@@ -1159,7 +1163,7 @@ function toHdbcdsSource(csn, options) {
1159
1163
  * @param {number} idx Path position
1160
1164
  * @returns {string} Rendered path step
1161
1165
  */
1162
- function renderPathStep(s, idx, ref, env, inline) {
1166
+ function renderPathStep( s, idx, ref, env ) {
1163
1167
  // Simple id or absolute name
1164
1168
  if (typeof s === 'string') {
1165
1169
  // HANA-specific extra magic (should actually be in forRelationalDB)
@@ -1210,7 +1214,7 @@ function toHdbcdsSource(csn, options) {
1210
1214
  }
1211
1215
  if (s.where) {
1212
1216
  // Filter, possibly with cardinality
1213
- result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env, inline, true)}]`;
1217
+ result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env)}]`;
1214
1218
  }
1215
1219
  return result;
1216
1220
  }
@@ -1222,7 +1226,7 @@ function toHdbcdsSource(csn, options) {
1222
1226
  * @param {object} x Expression with a val and/or literal property
1223
1227
  * @returns {string} Rendered expression
1224
1228
  */
1225
- function renderExpressionLiteral(x) {
1229
+ function renderExpressionLiteral( x ) {
1226
1230
  // Literal value, possibly with explicit 'literal' property
1227
1231
  switch (x.literal || typeof x.val) {
1228
1232
  case 'number':
@@ -1250,16 +1254,15 @@ function toHdbcdsSource(csn, options) {
1250
1254
  * Render the given expression x - which has a .func property
1251
1255
  *
1252
1256
  * @param {object} x
1253
- * @param {CdlRenderEnvironment} env
1254
1257
  * @returns {string}
1255
1258
  */
1256
- function renderExpressionFunc(x, env) {
1259
+ function renderExpressionFunc( x ) {
1257
1260
  const regex = RegExp(/^[a-zA-Z][\w#$]*$/, 'g');
1258
1261
  const funcName = regex.test(x.func) ? x.func : quoteId(x.func);
1259
1262
  // we can't quote functions with parens, issue warning if it is a reserved keyword
1260
1263
  if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
1261
1264
  warning(null, x.$location, { id: uppercaseAndUnderscore(funcName) }, 'The identifier $(ID) is a SAP HANA keyword');
1262
- return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', env));
1265
+ return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', this.env));
1263
1266
  }
1264
1267
 
1265
1268
  /**
@@ -1267,7 +1270,7 @@ function toHdbcdsSource(csn, options) {
1267
1270
  * @returns {string} Rendered expression
1268
1271
  * @todo no extra magic with x.param or x.global
1269
1272
  */
1270
- function renderExpressionRef(x, env) {
1273
+ function renderExpressionRef( x ) {
1271
1274
  if (!x.param && !x.global) {
1272
1275
  const magicReplacement = getVariableReplacement(x.ref, options);
1273
1276
  if (x.ref[0] === '$user') {
@@ -1294,7 +1297,7 @@ function toHdbcdsSource(csn, options) {
1294
1297
  return renderStringForHdbcds(magicReplacement);
1295
1298
  }
1296
1299
  }
1297
- return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, x.ref, env, this.inline)).join('.')}`;
1300
+ return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, x.ref, this.env)).join('.')}`;
1298
1301
  }
1299
1302
 
1300
1303
  /**
@@ -1306,16 +1309,16 @@ function toHdbcdsSource(csn, options) {
1306
1309
  * @param {CdlRenderEnvironment} env Environment
1307
1310
  * @returns {string} Rendered arguments
1308
1311
  */
1309
- function renderArgs(node, sep, env) {
1312
+ function renderArgs( node, sep, env ) {
1310
1313
  const args = node.args ? node.args : {};
1311
1314
  // Positional arguments
1312
1315
  if (Array.isArray(args))
1313
- return args.map(arg => renderExpr(arg, env, true, false, true)).join(', ');
1316
+ return args.map(arg => renderExpr(arg, env)).join(', ');
1314
1317
 
1315
1318
  // Named arguments (object/dict)
1316
1319
  else if (typeof args === 'object')
1317
1320
  // if this is a function param which is not a reference to the model, we must not quote it
1318
- return Object.keys(args).map(key => `${node.func ? key : formatIdentifier(key)} ${sep} ${renderExpr(args[key], env, true, false, true)}`).join(', ');
1321
+ return Object.keys(args).map(key => `${node.func ? key : formatIdentifier(key)} ${sep} ${renderExpr(args[key], env)}`).join(', ');
1319
1322
 
1320
1323
 
1321
1324
  throw new ModelError(`Unknown args: ${JSON.stringify(args)}`);
@@ -1327,7 +1330,7 @@ function toHdbcdsSource(csn, options) {
1327
1330
  * @param {CSN.Cardinality} card Cardinality
1328
1331
  * @returns {string} Rendered cardinality
1329
1332
  */
1330
- function renderCardinality(card) {
1333
+ function renderCardinality( card ) {
1331
1334
  if (!card)
1332
1335
  return '';
1333
1336
 
@@ -1350,7 +1353,7 @@ function toHdbcdsSource(csn, options) {
1350
1353
  * @param {object} obj Thing to render for
1351
1354
  * @returns {string} null/not null
1352
1355
  */
1353
- function renderNullability(obj /* , env */) {
1356
+ function renderNullability( obj /* , env */) {
1354
1357
  if (obj.notNull === undefined) {
1355
1358
  // Attribute not set at all
1356
1359
  return '';
@@ -1367,7 +1370,7 @@ function toHdbcdsSource(csn, options) {
1367
1370
  * @param {CdlRenderEnvironment} env Environment
1368
1371
  * @returns {string} Rendered foreign key
1369
1372
  */
1370
- function renderForeignKey(fKey, env) {
1373
+ function renderForeignKey( fKey, env ) {
1371
1374
  return `${renderExpr(fKey, env)}${fKey.as ? (` as ${fKey.as}`) : ''}`;
1372
1375
  }
1373
1376
 
@@ -1378,7 +1381,7 @@ function toHdbcdsSource(csn, options) {
1378
1381
  * @param {CSN.Element} elm Element to render type parameters for
1379
1382
  * @returns {string} Rendered type parameters
1380
1383
  */
1381
- function renderTypeParameters(elm /* , env */) {
1384
+ function renderTypeParameters( elm /* , env */) {
1382
1385
  const params = [];
1383
1386
  // Length, precision and scale (even if incomplete)
1384
1387
  if (elm.length !== undefined)
@@ -1405,7 +1408,7 @@ function toHdbcdsSource(csn, options) {
1405
1408
  * @param {CdlRenderEnvironment} env Environment
1406
1409
  * @returns {string} Uppercased and underscored absName
1407
1410
  */
1408
- function renderAbsoluteNamePlain(absName, env) {
1411
+ function renderAbsoluteNamePlain( absName, env ) {
1409
1412
  // Add using declaration
1410
1413
  env.topLevelAliases[absName] = {
1411
1414
  quotedName: formatIdentifier(uppercaseAndUnderscore(absName)),
@@ -1423,7 +1426,7 @@ function toHdbcdsSource(csn, options) {
1423
1426
  * @param {CdlRenderEnvironment} env Environment
1424
1427
  * @returns {string} absName, with correct quotes
1425
1428
  */
1426
- function renderAbsoluteNameWithQuotes(absName, env) {
1429
+ function renderAbsoluteNameWithQuotes( absName, env ) {
1427
1430
  // Special case: If the top-level artifact name is not a valid artifact name, it came from an unchecked annotation
1428
1431
  // and must be left as it is (just quoted)
1429
1432
  let topLevelName = getRootArtifactName(absName, csn);
@@ -1481,7 +1484,7 @@ function toHdbcdsSource(csn, options) {
1481
1484
  * @param {string} topLevelName Name of a top-level artifact
1482
1485
  * @returns {string} Appropriate __alias
1483
1486
  */
1484
- function createTopLevelAliasName(topLevelName) {
1487
+ function createTopLevelAliasName( topLevelName ) {
1485
1488
  // FIXME: We should rather check for conflicts than just using something obscure like this ...
1486
1489
  return `__${topLevelName.replace(/::/g, '__').replace(/\./g, '_')}`;
1487
1490
  }
@@ -1493,7 +1496,7 @@ function toHdbcdsSource(csn, options) {
1493
1496
  * @param {CdlRenderEnvironment} env Environment
1494
1497
  * @returns {string} Usings for the given artifact
1495
1498
  */
1496
- function renderUsings(artifactName, env) {
1499
+ function renderUsings( artifactName, env ) {
1497
1500
  const distinct = {};
1498
1501
  Object.keys(env.topLevelAliases)
1499
1502
  .filter(name => env.topLevelAliases[name].quotedAlias !== formatIdentifier(uppercaseAndUnderscore(artifactName))) // avoid "using FOO as FOO" in FOO.cds
@@ -1510,7 +1513,7 @@ function toHdbcdsSource(csn, options) {
1510
1513
  * see cap/cds-compiler#8269 for details
1511
1514
  * @param {string} name of the native db object
1512
1515
  */
1513
- function checkForNameClashesWithNativeObject(name) {
1516
+ function checkForNameClashesWithNativeObject( name ) {
1514
1517
  const possibleShadowName = getNamePrefix(env.topLevelAliases[name].quotedName);
1515
1518
  const mightBeShadowedBy = csn.definitions[possibleShadowName];
1516
1519
  if (mightBeShadowedBy) {
@@ -1521,7 +1524,7 @@ function toHdbcdsSource(csn, options) {
1521
1524
  }
1522
1525
  }
1523
1526
 
1524
- function isArtifactRendered(art, artName) {
1527
+ function isArtifactRendered( art, artName ) {
1525
1528
  const isHanaCdsContext = art.kind === 'service' || art.kind === 'context';
1526
1529
  if (isHanaCdsContext)
1527
1530
  return isContextRendered(artName);
@@ -1538,7 +1541,7 @@ function toHdbcdsSource(csn, options) {
1538
1541
  * @param {string} contextName
1539
1542
  * @returns {boolean} true if a context/service will be rendered as a SAP HANA CDS context.
1540
1543
  */
1541
- function isContextRendered(contextName) {
1544
+ function isContextRendered( contextName ) {
1542
1545
  const subArtifacts = getSubArtifacts(contextName);
1543
1546
  return Object.entries(subArtifacts).some(([ artName, art ]) => {
1544
1547
  if (art.kind === 'context')
@@ -1554,7 +1557,7 @@ function toHdbcdsSource(csn, options) {
1554
1557
  * "com.sap.foo.native.object" --> com
1555
1558
  * "com.sap.foo::native.object" --> com.sap.foo.native
1556
1559
  */
1557
- function getNamePrefix(usingName) {
1560
+ function getNamePrefix( usingName ) {
1558
1561
  usingName = usingName.replace(/"/g, '');
1559
1562
  if (usingName.indexOf('::') !== -1) {
1560
1563
  const parts = usingName.split('::');
@@ -1576,7 +1579,7 @@ function toHdbcdsSource(csn, options) {
1576
1579
  * @param {CdlRenderEnvironment} env Environment
1577
1580
  * @returns {string} Rendered namespace declaration
1578
1581
  */
1579
- function renderNamespaceDeclaration(topLevelName, env) {
1582
+ function renderNamespaceDeclaration( topLevelName, env ) {
1580
1583
  if (plainNames) {
1581
1584
  // No namespaces in plain mode
1582
1585
  return '';
@@ -1640,7 +1643,7 @@ function toHdbcdsSource(csn, options) {
1640
1643
  * @param {string} id Name prefix to add
1641
1644
  * @returns {CdlRenderEnvironment} New environment with added prefix
1642
1645
  */
1643
- function addNamePrefix(env, id) {
1646
+ function addNamePrefix( env, id ) {
1644
1647
  return Object.assign({}, env, { namePrefix: `${env.namePrefix + quoteId(id)}.` });
1645
1648
  }
1646
1649
 
@@ -1650,7 +1653,7 @@ function toHdbcdsSource(csn, options) {
1650
1653
  * @param {CdlRenderEnvironment} env Current environment
1651
1654
  * @returns {CdlRenderEnvironment} New environment with increased indent
1652
1655
  */
1653
- function increaseIndent(env) {
1656
+ function increaseIndent( env ) {
1654
1657
  return Object.assign({}, env, { namePrefix: '', indent: `${env.indent} ` });
1655
1658
  }
1656
1659
 
@@ -1660,7 +1663,7 @@ function toHdbcdsSource(csn, options) {
1660
1663
  * @param {string} path Path to quote
1661
1664
  * @returns {string} Quoted path
1662
1665
  */
1663
- function quotePathString(path) {
1666
+ function quotePathString( path ) {
1664
1667
  // "foo"."bar"."wiz"."blub"
1665
1668
  return path.split('.').map(quoteId).join('.');
1666
1669
  }
@@ -1672,7 +1675,7 @@ function toHdbcdsSource(csn, options) {
1672
1675
  * @param {string} absPath Absolute path to quote
1673
1676
  * @returns {string} Quoted path
1674
1677
  */
1675
- function quoteAbsolutePathString(absPath) {
1678
+ function quoteAbsolutePathString( absPath ) {
1676
1679
  const namespace = getNamespace(csn, absPath);
1677
1680
  const resultingName = getResultingName(csn, options.sqlMapping, absPath);
1678
1681
 
@@ -1688,7 +1691,7 @@ function toHdbcdsSource(csn, options) {
1688
1691
  * @param {string} id Identifier to quote
1689
1692
  * @returns {string} Properly quoted identifier
1690
1693
  */
1691
- function quoteId(id) {
1694
+ function quoteId( id ) {
1692
1695
  // Should only ever be called for real IDs (i.e. no dots inside)
1693
1696
  if (id.indexOf('.') !== -1)
1694
1697
  throw new ModelError(`HDBCDS: Tried to quote id with dot: ${id}`);
@@ -1712,7 +1715,7 @@ function toHdbcdsSource(csn, options) {
1712
1715
  * @param {string} absName Absolute name
1713
1716
  * @returns {string} Correctly quoted absName
1714
1717
  */
1715
- function quoteAbsoluteNameAsId(absName) {
1718
+ function quoteAbsoluteNameAsId( absName ) {
1716
1719
  const resultingName = getResultingName(csn, options.sqlMapping, absName);
1717
1720
 
1718
1721
  if (hdbcdsNames) {
@@ -1729,7 +1732,7 @@ function toHdbcdsSource(csn, options) {
1729
1732
  * @param {string} id Identifier
1730
1733
  * @returns {string} Quoted/uppercased id
1731
1734
  */
1732
- function formatIdentifier(id) {
1735
+ function formatIdentifier( id ) {
1733
1736
  id = plainNames ? id.toUpperCase() : id;
1734
1737
  return quoteId(id);
1735
1738
  }
@@ -1743,7 +1746,7 @@ function toHdbcdsSource(csn, options) {
1743
1746
  * @param {CSN.Path} [location] Optional location for the warning.
1744
1747
  * @returns {string} Quoted/uppercased id
1745
1748
  */
1746
- function formatParamIdentifier(id, location) {
1749
+ function formatParamIdentifier( id, location ) {
1747
1750
  // Warn if colliding with HANA keyword, but do not quote for plain
1748
1751
  // --> quoted reserved words as param lead to a weird deployment error
1749
1752
  if (keywords.hdbcds.includes(uppercaseAndUnderscore(id)))
@@ -1772,7 +1775,7 @@ function toHdbcdsSource(csn, options) {
1772
1775
  * @param {boolean} [fallthrough=false] For certain artifacts, plain-rendering is supposed to look like quoted/hdbcds
1773
1776
  * @returns {string} Artifact name ready for rendering
1774
1777
  */
1775
- function renderArtifactName(artifactName, env, fallthrough = false) {
1778
+ function renderArtifactName( artifactName, env, fallthrough = false ) {
1776
1779
  if (plainNames && !fallthrough)
1777
1780
  return formatIdentifier(uppercaseAndUnderscore(artifactName));
1778
1781
  // hdbcds with quoted or hdbcds naming
@@ -1789,7 +1792,7 @@ function toHdbcdsSource(csn, options) {
1789
1792
  * @param {string} name Name to transform
1790
1793
  * @returns {string} Uppercased and underscored name
1791
1794
  */
1792
- function uppercaseAndUnderscore(name) {
1795
+ function uppercaseAndUnderscore( name ) {
1793
1796
  // Always replace '.' by '_' and uppercase
1794
1797
  return name.replace(/\./g, '_').toUpperCase();
1795
1798
  }
@@ -1804,9 +1807,9 @@ function toHdbcdsSource(csn, options) {
1804
1807
  * @property {{[name: string]: {
1805
1808
  quotedName: string,
1806
1809
  quotedAlias: string
1807
- }}} topLevelAliases Dictionary of aliases for used artifact names
1810
+ }}} [topLevelAliases] Dictionary of aliases for used artifact names
1808
1811
  *
1809
- * @property {string} namePrefix Current name prefix (including trailing dot if not empty)
1812
+ * @property {string} [namePrefix] Current name prefix (including trailing dot if not empty)
1810
1813
  * @property {boolean} [skipKeys] Skip rendering keys in subqueries
1811
1814
  * @property {CSN.Artifact} [_artifact] The original view artifact, used when rendering queries
1812
1815
  */