@sap/cds-compiler 2.11.4 → 2.12.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 (80) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/bin/cds_update_identifiers.js +7 -7
  3. package/bin/cdsc.js +9 -10
  4. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  5. package/doc/CHANGELOG_BETA.md +12 -0
  6. package/lib/api/main.js +2 -0
  7. package/lib/api/options.js +2 -2
  8. package/lib/base/message-registry.js +31 -2
  9. package/lib/base/model.js +1 -0
  10. package/lib/base/optionProcessorHelper.js +97 -69
  11. package/lib/checks/.eslintrc.json +2 -0
  12. package/lib/checks/actionsFunctions.js +2 -1
  13. package/lib/checks/foreignKeys.js +4 -4
  14. package/lib/checks/managedInType.js +4 -4
  15. package/lib/checks/queryNoDbArtifacts.js +1 -3
  16. package/lib/checks/sql-snippets.js +93 -0
  17. package/lib/checks/validator.js +8 -0
  18. package/lib/compiler/assert-consistency.js +5 -3
  19. package/lib/compiler/base.js +0 -1
  20. package/lib/compiler/checks.js +32 -9
  21. package/lib/compiler/definer.js +25 -4
  22. package/lib/compiler/index.js +1 -1
  23. package/lib/compiler/propagator.js +3 -2
  24. package/lib/compiler/resolver.js +97 -6
  25. package/lib/compiler/shared.js +12 -1
  26. package/lib/compiler/utils.js +7 -0
  27. package/lib/edm/annotations/genericTranslation.js +34 -17
  28. package/lib/edm/annotations/preprocessAnnotations.js +1 -1
  29. package/lib/edm/csn2edm.js +1 -1
  30. package/lib/edm/edm.js +8 -8
  31. package/lib/edm/edmPreprocessor.js +30 -23
  32. package/lib/edm/edmUtils.js +11 -12
  33. package/lib/gen/Dictionary.json +82 -40
  34. package/lib/gen/language.checksum +1 -1
  35. package/lib/gen/language.interp +3 -1
  36. package/lib/gen/language.tokens +15 -14
  37. package/lib/gen/languageLexer.interp +9 -1
  38. package/lib/gen/languageLexer.js +830 -779
  39. package/lib/gen/languageLexer.tokens +7 -6
  40. package/lib/gen/languageParser.js +2401 -2282
  41. package/lib/json/from-csn.js +47 -16
  42. package/lib/json/to-csn.js +17 -5
  43. package/lib/language/antlrParser.js +3 -3
  44. package/lib/language/docCommentParser.js +1 -1
  45. package/lib/language/genericAntlrParser.js +68 -51
  46. package/lib/language/language.g4 +128 -74
  47. package/lib/language/multiLineStringParser.js +536 -0
  48. package/lib/main.d.ts +5 -3
  49. package/lib/main.js +3 -2
  50. package/lib/model/csnRefs.js +116 -68
  51. package/lib/model/csnUtils.js +40 -48
  52. package/lib/model/enrichCsn.js +30 -14
  53. package/lib/optionProcessor.js +3 -3
  54. package/lib/render/DuplicateChecker.js +1 -1
  55. package/lib/render/manageConstraints.js +1 -1
  56. package/lib/render/toCdl.js +193 -79
  57. package/lib/render/toHdbcds.js +179 -95
  58. package/lib/render/toRename.js +7 -10
  59. package/lib/render/toSql.js +57 -40
  60. package/lib/render/utils/common.js +24 -5
  61. package/lib/render/utils/sql.js +6 -4
  62. package/lib/transform/braceExpression.js +4 -2
  63. package/lib/transform/db/associations.js +389 -0
  64. package/lib/transform/db/cdsPersistence.js +150 -0
  65. package/lib/transform/db/constraints.js +6 -4
  66. package/lib/transform/db/draft.js +3 -2
  67. package/lib/transform/db/expansion.js +4 -5
  68. package/lib/transform/db/flattening.js +5 -6
  69. package/lib/transform/db/temporal.js +236 -0
  70. package/lib/transform/db/transformExists.js +36 -23
  71. package/lib/transform/forHanaNew.js +35 -626
  72. package/lib/transform/forOdataNew.js +5 -4
  73. package/lib/transform/localized.js +3 -14
  74. package/lib/transform/odata/generateForeignKeyElements.js +2 -2
  75. package/lib/transform/transformUtilsNew.js +13 -13
  76. package/lib/transform/translateAssocsToJoins.js +8 -8
  77. package/lib/transform/universalCsnEnricher.js +217 -47
  78. package/lib/utils/file.js +2 -1
  79. package/lib/utils/timetrace.js +8 -2
  80. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- getParentNameOf, getLastPartOf, getLastPartOfRef,
4
+ getLastPartOf, getLastPartOfRef,
5
5
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
6
- getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement,
6
+ getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement, hasAnnotationValue,
7
7
  } = require('../model/csnUtils');
8
8
  const keywords = require('../base/keywords');
9
9
  const {
10
10
  renderFunc, beautifyExprArray, getRealName, addContextMarkers, addIntermediateContexts, cdsToSqlTypes,
11
- hasHanaComment, getHanaComment, findElement, funcWithoutParen,
11
+ hasHanaComment, getHanaComment, findElement, funcWithoutParen, getSqlSnippets,
12
12
  } = require('./utils/common');
13
13
  const {
14
14
  renderReferentialConstraint,
@@ -60,8 +60,7 @@ function toHdbcdsSource(csn, options) {
60
60
 
61
61
  checkCSNVersion(csn, options);
62
62
 
63
- const result = Object.create(null);
64
-
63
+ const hdbcdsResult = Object.create(null);
65
64
 
66
65
  const globalDuplicateChecker = new DuplicateChecker(options.sqlMapping); // registry for all artifact names and element names
67
66
 
@@ -100,17 +99,17 @@ function toHdbcdsSource(csn, options) {
100
99
  Object.entries(art.$tableConstraints.referential)
101
100
  .forEach(([ fileName, referentialConstraint ]) => {
102
101
  referentialConstraints[fileName] = renderReferentialConstraint(
103
- referentialConstraint, '', renderToUppercase, csn, options, false
102
+ referentialConstraint, '', renderToUppercase, csn, options
104
103
  );
105
104
  });
106
105
  Object.entries(referentialConstraints)
107
- .forEach( ([ fileName, constraint ]) => {
106
+ .forEach(([ fileName, constraint ]) => {
108
107
  hdbconstraint[fileName] = constraint;
109
108
  });
110
109
  }
111
110
  });
112
- result.hdbcds = hdbcds;
113
- result.hdbconstraint = hdbconstraint;
111
+ hdbcdsResult.hdbcds = hdbcds;
112
+ hdbcdsResult.hdbconstraint = hdbconstraint;
114
113
 
115
114
  if (globalDuplicateChecker)
116
115
  globalDuplicateChecker.check(error, options); // perform duplicates check
@@ -119,7 +118,7 @@ function toHdbcdsSource(csn, options) {
119
118
 
120
119
  throwWithError();
121
120
  timetrace.stop();
122
- return options.testMode ? sort(result) : result;
121
+ return options.testMode ? sort(hdbcdsResult) : hdbcdsResult;
123
122
 
124
123
  /**
125
124
  * Sort the given object alphabetically
@@ -224,7 +223,7 @@ function toHdbcdsSource(csn, options) {
224
223
  const parts = containee.split('.');
225
224
  const prefixLength = contextName.split('.').length;
226
225
 
227
- for (let i = parts.length - 1; i > prefixLength; i-- ) {
226
+ for (let i = parts.length - 1; i > prefixLength; i--) {
228
227
  const prefix = parts.slice(0, i).join('.');
229
228
  const art = csn.definitions[prefix];
230
229
  if (art && (art.kind === 'context' || art.kind === 'service'))
@@ -291,7 +290,7 @@ function toHdbcdsSource(csn, options) {
291
290
  function renderContext(artifactName, art, env, isShadowed) {
292
291
  let result = '';
293
292
  if (!isShadowed)
294
- isShadowed = contextIsShadowed(artifactName, csn);
293
+ isShadowed = contextIsShadowed(artifactName);
295
294
  if (isShadowed) {
296
295
  const subArtifacts = getSubArtifacts(artifactName);
297
296
  for (const name in subArtifacts)
@@ -318,10 +317,9 @@ function toHdbcdsSource(csn, options) {
318
317
  * non-context/service/namespace definition
319
318
  *
320
319
  * @param {string} artifactName
321
- * @param {CSN.Model} csn
322
320
  * @returns {boolean}
323
321
  */
324
- function contextIsShadowed(artifactName, csn) {
322
+ function contextIsShadowed(artifactName) {
325
323
  if (artifactName.indexOf('.') === -1)
326
324
  return false;
327
325
 
@@ -395,6 +393,12 @@ function toHdbcdsSource(csn, options) {
395
393
  if (hasHanaComment(art, options))
396
394
  result += `${env.indent}@Comment: '${getEscapedHanaComment(art)}'\n`;
397
395
 
396
+ // tables can have @sql.prepend and @sql.append
397
+ const { front, back } = getSqlSnippets(options, art);
398
+
399
+ if (front) // attach @sql.prepend after adding @Comment annotation
400
+ result += front;
401
+
398
402
  result += `${env.indent + (art.abstract ? 'abstract ' : '')}entity ${normalizedArtifactName}`;
399
403
  if (art.includes) {
400
404
  // Includes are never flattened (don't exist in HANA)
@@ -412,8 +416,12 @@ function toHdbcdsSource(csn, options) {
412
416
 
413
417
  duplicateChecker.check(error);
414
418
  result += `${env.indent}}`;
415
- result += `${renderTechnicalConfiguration(art.technicalConfig, env)};\n`;
416
- return result;
419
+ result += `${renderTechnicalConfiguration(art.technicalConfig, env)}`;
420
+
421
+ if (back)
422
+ result += back;
423
+
424
+ return `${result};\n`;
417
425
  }
418
426
 
419
427
  /**
@@ -429,9 +437,8 @@ function toHdbcdsSource(csn, options) {
429
437
  if (!element.target)
430
438
  return;
431
439
 
432
- let alias = element['@cds.persistence.name'];
433
440
  if (uppercaseAndUnderscore(element.target) === element['@cds.persistence.name']) {
434
- alias = createTopLevelAliasName(element['@cds.persistence.name']);
441
+ let alias = createTopLevelAliasName(element['@cds.persistence.name']);
435
442
  // calculate new alias if it would conflict with other csn.Artifact
436
443
  while (csn.definitions[alias])
437
444
  alias = createTopLevelAliasName(alias);
@@ -556,13 +563,19 @@ function toHdbcdsSource(csn, options) {
556
563
  result += `${env.indent}@Comment: '${getEscapedHanaComment(elm)}'\n`;
557
564
 
558
565
  result += env.indent + (elm.key && !isSubElement ? 'key ' : '') +
559
- (elm.masked ? 'masked ' : '') +
560
- quotedElementName + (omitColon ? ' ' : ' : ') +
561
- renderTypeReference(elm, env) +
562
- renderNullability(elm);
566
+ (elm.masked ? 'masked ' : '') +
567
+ quotedElementName + (omitColon ? ' ' : ' : ') +
568
+ renderTypeReference(elm, env) +
569
+ renderNullability(elm);
563
570
  if (elm.default)
564
571
  result += ` default ${renderExpr(elm.default, env)}`;
565
572
 
573
+ // (table) elements can only have a @sql.append
574
+ const { back } = getSqlSnippets(options, elm);
575
+
576
+ if (back)
577
+ result += back;
578
+
566
579
  return `${result};\n`;
567
580
  }
568
581
 
@@ -760,7 +773,14 @@ function toHdbcdsSource(csn, options) {
760
773
  }
761
774
  env._artifact = art;
762
775
  result += renderQuery(getNormalizedQuery(art).query, true, env, artifactPath.concat(art.projection ? 'projection' : 'query'), art.elements);
776
+
777
+ // views can only have a @sql.append
778
+ const { back } = getSqlSnippets(options, art);
779
+ if (back)
780
+ result += back;
781
+
763
782
  result += ';\n';
783
+
764
784
  return result;
765
785
  }
766
786
 
@@ -829,72 +849,73 @@ function toHdbcdsSource(csn, options) {
829
849
  result += `${env.indent}}`;
830
850
  }
831
851
  if (select.excluding) {
832
- result += ` excluding {\n${select.excluding.map(id => `${childEnv.indent}${formatIdentifier(id)}`).join(',\n')}\n`;
852
+ const excludingList = select.excluding.map(id => `${childEnv.indent}${formatIdentifier(id)}`).join(',\n');
853
+ result += ` excluding {\n${excludingList}\n`;
833
854
  result += `${env.indent}}`;
834
855
  }
835
856
 
836
- return renderSelectProperties(select, result);
837
-
838
- /**
839
- * Render WHERE, GROUP BY, HAVING, ORDER BY and LIMIT clause
840
- *
841
- * @param {CSN.QuerySelect} select
842
- * @param {string} alreadyRendered The query as it has been rendered so far
843
- * @returns {string} The query with WHERE etc. added
844
- */
845
- function renderSelectProperties(select, alreadyRendered) {
846
- if (select.where)
847
- alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
857
+ return renderSelectProperties(select, result, env);
858
+ }
848
859
 
849
- if (select.groupBy)
850
- alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env)).join(', ')}`;
860
+ /**
861
+ * Render WHERE, GROUP BY, HAVING, ORDER BY and LIMIT clause
862
+ *
863
+ * @param {CSN.QuerySelect} select
864
+ * @param {string} alreadyRendered The query as it has been rendered so far
865
+ * @param {CdlRenderEnvironment} env Environment
866
+ * @returns {string} The query with WHERE etc. added
867
+ */
868
+ function renderSelectProperties(select, alreadyRendered, env) {
869
+ if (select.where)
870
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
851
871
 
852
- if (select.having)
853
- alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env, true, true)}`;
872
+ if (select.groupBy)
873
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env)).join(', ')}`;
854
874
 
855
- if (select.orderBy)
856
- alreadyRendered += `${continueIndent(alreadyRendered, env)}order by ${select.orderBy.map(entry => renderOrderByEntry(entry, env)).join(', ')}`;
875
+ if (select.having)
876
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env, true, true)}`;
857
877
 
858
- if (select.limit)
859
- alreadyRendered += `${continueIndent(alreadyRendered, env)}${renderLimit(select.limit, env)}`;
878
+ if (select.orderBy)
879
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}order by ${select.orderBy.map(entry => renderOrderByEntry(entry, env)).join(', ')}`;
860
880
 
861
- return alreadyRendered;
862
- }
881
+ if (select.limit)
882
+ alreadyRendered += `${continueIndent(alreadyRendered, env)}${renderLimit(select.limit, env)}`;
863
883
 
884
+ return alreadyRendered;
885
+ }
864
886
 
865
- /**
866
- * Utility function to make sure that we continue with the same indentation in WHERE, GROUP BY, ... after a closing curly brace and beyond
867
- *
868
- * @param {string} result Result of a previous render step
869
- * @param {CdlRenderEnvironment} env Environment
870
- * @returns {string} String to join with
871
- */
872
- function continueIndent(result, env) {
873
- if (result.endsWith('}') || result.endsWith('})')) {
874
- // The preceding clause ended with '}', just append after that
875
- return ' ';
876
- }
877
- // Otherwise, start new line and indent normally
878
- return `\n${increaseIndent(env).indent}`;
887
+ /**
888
+ * Utility function to make sure that we continue with the same indentation in WHERE, GROUP BY, ... after a closing curly brace and beyond
889
+ *
890
+ * @param {string} result Result of a previous render step
891
+ * @param {CdlRenderEnvironment} env Environment
892
+ * @returns {string} String to join with
893
+ */
894
+ function continueIndent(result, env) {
895
+ if (result.endsWith('}') || result.endsWith('})')) {
896
+ // The preceding clause ended with '}', just append after that
897
+ return ' ';
879
898
  }
899
+ // Otherwise, start new line and indent normally
900
+ return `\n${increaseIndent(env).indent}`;
901
+ }
880
902
 
881
- /**
882
- * Render a query's LIMIT clause, which may have also have OFFSET.
883
- *
884
- * @param {CSN.QueryLimit} limit CSN limit clause
885
- * @param {CdlRenderEnvironment} env Environment
886
- * @returns {string} Rendered limit clause
887
- */
888
- function renderLimit(limit, env) {
889
- let result = '';
890
- if (limit.rows !== undefined)
891
- result += `limit ${renderExpr(limit.rows, env)}`;
903
+ /**
904
+ * Render a query's LIMIT clause, which may have also have OFFSET.
905
+ *
906
+ * @param {CSN.QueryLimit} limit CSN limit clause
907
+ * @param {CdlRenderEnvironment} env Environment
908
+ * @returns {string} Rendered limit clause
909
+ */
910
+ function renderLimit(limit, env) {
911
+ let result = '';
912
+ if (limit.rows !== undefined)
913
+ result += `limit ${renderExpr(limit.rows, env)}`;
892
914
 
893
- if (limit.offset !== undefined)
894
- result += `${result !== '' ? `\n${increaseIndent(env).indent}` : ''}offset ${renderExpr(limit.offset, env)}`;
915
+ if (limit.offset !== undefined)
916
+ result += `${result !== '' ? `\n${increaseIndent(env).indent}` : ''}offset ${renderExpr(limit.offset, env)}`;
895
917
 
896
- return result;
897
- }
918
+ return result;
898
919
  }
899
920
 
900
921
  /**
@@ -943,7 +964,7 @@ function toHdbcdsSource(csn, options) {
943
964
  if (art.kind === 'aspect' || art.kind === 'type' && !hdbcdsNames || art.kind === 'type' && hdbcdsNames && !art.elements)
944
965
  return '';
945
966
  let result = '';
946
- result += `${env.indent + (art.kind )} ${renderArtifactName(artifactName, env, true)}`;
967
+ result += `${env.indent + (art.kind)} ${renderArtifactName(artifactName, env, true)}`;
947
968
  if (art.includes) {
948
969
  // Includes are never flattened (don't exist in HANA)
949
970
  result += ` : ${art.includes.map(name => renderAbsoluteNameWithQuotes(name, env)).join(', ')}`;
@@ -968,7 +989,7 @@ function toHdbcdsSource(csn, options) {
968
989
  * Render a reference to a type used by 'elm' (named or inline)
969
990
  * Allow suppressing enum-rendering - used in columns for example
970
991
  *
971
- * @param {CSN.Element} elm Element using the type reference
992
+ * @param {object} elm Element using the type reference
972
993
  * @param {CdlRenderEnvironment} env Environment
973
994
  * @returns {string} Rendered type reference
974
995
  */
@@ -1091,33 +1112,34 @@ function toHdbcdsSource(csn, options) {
1091
1112
  * Render an expression (including paths and values) or condition 'x'.
1092
1113
  * (no trailing LF, don't indent if inline)
1093
1114
  *
1094
- * @param {any} x Expression to render
1115
+ * @param {any} expr Expression to render
1095
1116
  * @param {CdlRenderEnvironment} env Environment
1096
- * @param {boolean} [inline=true] Wether to render inline
1117
+ * @param {boolean} [inline=true] Whether to render inline
1097
1118
  * @param {boolean} [inExpr=false] Whether the expression is already inside another expression
1098
1119
  * @returns {string} Rendered expression
1099
1120
  */
1100
- function renderExpr(x, env, inline = true, inExpr = false) {
1121
+ function renderExpr(expr, env, inline = true, inExpr = false) {
1101
1122
  // Compound expression
1102
- if (Array.isArray(x))
1103
- return beautifyExprArray(x.map(item => renderExpr(item, env, inline, inExpr)));
1123
+ if (Array.isArray(expr))
1124
+ return beautifyExprArray(expr.map(item => renderExpr(item, env, inline, inExpr)));
1104
1125
 
1105
- if (typeof x === 'object' && x !== null) {
1106
- if (inExpr && x.cast && x.cast.type)
1107
- return renderExplicitTypeCast(renderExprObject());
1108
- return renderExprObject();
1126
+ if (typeof expr === 'object' && expr !== null) {
1127
+ if (inExpr && expr.cast && expr.cast.type)
1128
+ return renderExplicitTypeCast(renderExprObject(expr));
1129
+ return renderExprObject(expr);
1109
1130
  }
1110
1131
 
1111
1132
  // Not a literal value but part of an operator, function etc - just leave as it is
1112
- return x;
1133
+ return expr;
1113
1134
 
1114
1135
 
1115
1136
  /**
1116
1137
  * Various special cases represented as objects
1117
1138
  *
1139
+ * @param {object} x Expression
1118
1140
  * @returns {string} Rendered expression object
1119
1141
  */
1120
- function renderExprObject() {
1142
+ function renderExprObject(x) {
1121
1143
  if (x.list) {
1122
1144
  // set "inExpr" to false: treat list elements as new expressions
1123
1145
  return `(${x.list.map(item => renderExpr(item, env, inline, false)).join(', ')})`;
@@ -1145,7 +1167,7 @@ function toHdbcdsSource(csn, options) {
1145
1167
  // we can't quote functions with parens, issue warning if it is a reserved keyword
1146
1168
  if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
1147
1169
  warning(null, x.$location, `The identifier “${uppercaseAndUnderscore(funcName)}“ is a SAP HANA keyword`);
1148
- return renderFunc( funcName, x, 'hana', a => renderArgs(a, '=>', env) );
1170
+ return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', env));
1149
1171
  }
1150
1172
  // Nested expression
1151
1173
  else if (x.xpr) {
@@ -1242,10 +1264,10 @@ function toHdbcdsSource(csn, options) {
1242
1264
  * @returns {string} Rendered cast()
1243
1265
  */
1244
1266
  function renderExplicitTypeCast(value) {
1245
- let typeRef = renderTypeReference(x.cast, env);
1267
+ let typeRef = renderTypeReference(expr.cast, env);
1246
1268
 
1247
1269
  // inside a cast expression, the cds and hana cds types need to be mapped to hana sql types
1248
- const hanaSqlType = cdsToSqlTypes.hana[x.cast.type] || cdsToSqlTypes.standard[x.cast.type];
1270
+ const hanaSqlType = cdsToSqlTypes.hana[expr.cast.type] || cdsToSqlTypes.standard[expr.cast.type];
1249
1271
  if (hanaSqlType) {
1250
1272
  const typeRefWithoutParams = typeRef.substring(0, typeRef.indexOf('(')) || typeRef;
1251
1273
  typeRef = typeRef.replace(typeRefWithoutParams, hanaSqlType);
@@ -1521,9 +1543,70 @@ function toHdbcdsSource(csn, options) {
1521
1543
  Object.keys(env.topLevelAliases)
1522
1544
  .filter(name => env.topLevelAliases[name].quotedAlias !== formatIdentifier(uppercaseAndUnderscore(artifactName))) // avoid "using FOO as FOO" in FOO.cds
1523
1545
  .forEach((name) => {
1546
+ const nativeObjectExists = csn.definitions[name] && hasAnnotationValue(csn.definitions[name], '@cds.persistence.exists');
1547
+ if (!plainNames && nativeObjectExists)
1548
+ checkForNameClashesWithNativeObject(name);
1524
1549
  distinct[`using ${env.topLevelAliases[name].quotedName} as ${env.topLevelAliases[name].quotedAlias};\n`] = '';
1525
1550
  });
1551
+ /**
1552
+ * If we generate a `using <native object> from <bar>` clause,
1553
+ * we warn if we generate a SAP HANA CDS artifact which would hide the
1554
+ * native DB object from being found by the SAP HANA CDS compiler
1555
+ * see cap/cds-compiler#8269 for details
1556
+ * @param {string} name of the native db object
1557
+ */
1558
+ function checkForNameClashesWithNativeObject(name) {
1559
+ const possibleShadowName = getNamePrefix(env.topLevelAliases[name].quotedName);
1560
+ const mightBeShadowedBy = csn.definitions[possibleShadowName];
1561
+ if (mightBeShadowedBy) {
1562
+ const artifactWillBeRendered = isArtifactRendered(mightBeShadowedBy, possibleShadowName);
1563
+ // only warn if actually rendered to HANA CDS
1564
+ if (artifactWillBeRendered)
1565
+ warning('anno-hidden-exists', [ 'definitions', name ], { name: possibleShadowName }, 'Native database object is hidden by a definition starting with $(NAME)');
1566
+ }
1567
+ }
1568
+
1569
+ function isArtifactRendered(art, artName) {
1570
+ const isHanaCdsContext = art.kind === 'service' || art.kind === 'context';
1571
+ if (isHanaCdsContext)
1572
+ return isContextRendered(artName);
1573
+ if ([ 'action', 'function', 'event' ].includes(art.kind) || options.sqlMapping !== 'hdbcds' && art.kind === 'type')
1574
+ return false;
1575
+ return !(hasAnnotationValue(art, '@cds.persistence.exists') || hasAnnotationValue(art, '@cds.persistence.skip'));
1576
+ }
1577
+
1578
+ /**
1579
+ * Check if there is at least one entity which will be rendered as SAP HANA CDS entity
1580
+ * inside the given context (or in its sub-contexts).
1581
+ * Or in other words: If the context will be rendered as a SAP HANA CDS context in the end.
1582
+ *
1583
+ * @param {string} contextName
1584
+ * @returns {boolean} true if a context/service will be rendered as a SAP HANA CDS context.
1585
+ */
1586
+ function isContextRendered(contextName) {
1587
+ const subArtifacts = getSubArtifacts(contextName);
1588
+ return Object.entries(subArtifacts).some(([ artName, art ]) => {
1589
+ if (art.kind === 'context')
1590
+ return isContextRendered(`${contextName}.${artName}`);
1591
+ return isArtifactRendered(art, artName);
1592
+ });
1593
+ }
1526
1594
 
1595
+ /**
1596
+ * @param {string} usingName the string which appears in the `using <string> from ..` including the quotes
1597
+ * @returns the prefix of the `using` name.
1598
+ * @example
1599
+ * "com.sap.foo.native.object" --> com
1600
+ * "com.sap.foo::native.object" --> com.sap.foo.native
1601
+ */
1602
+ function getNamePrefix(usingName) {
1603
+ usingName = usingName.replace(/"/g, '');
1604
+ if (usingName.indexOf('::') !== -1) {
1605
+ const parts = usingName.split('::');
1606
+ return `${parts[0]}.${parts[1].split('.')[0]}`;
1607
+ }
1608
+ return usingName.split('.')[0];
1609
+ }
1527
1610
  return Object.keys(distinct).join('');
1528
1611
  }
1529
1612
 
@@ -1676,13 +1759,14 @@ function toHdbcdsSource(csn, options) {
1676
1759
  * @returns {string} Correctly quoted absname
1677
1760
  */
1678
1761
  function quoteAbsoluteNameAsId(absname) {
1762
+ const resultingName = getResultingName(csn, options.sqlMapping, absname);
1763
+
1679
1764
  if (hdbcdsNames) {
1680
- const topLevelName = getRootArtifactName(absname, csn);
1681
- const namespace = getParentNameOf(topLevelName);
1765
+ const namespace = getNamespace(csn, absname);
1682
1766
  if (namespace)
1683
- return `"${(`${namespace}::${absname.substring(namespace.length + 1)}`).replace(/"/g, '""')}"`;
1767
+ return `"${(`${namespace}::${resultingName.substring(namespace.length + 2)}`).replace(/"/g, '""')}"`;
1684
1768
  }
1685
- return `"${absname.replace(/"/g, '""')}"`;
1769
+ return `"${resultingName.replace(/"/g, '""')}"`;
1686
1770
  }
1687
1771
 
1688
1772
  /**
@@ -1737,7 +1821,7 @@ function toHdbcdsSource(csn, options) {
1737
1821
  function renderArtifactName(artifactName, env, fallthrough = false) {
1738
1822
  if (plainNames && !fallthrough)
1739
1823
  return formatIdentifier(uppercaseAndUnderscore(artifactName));
1740
- // hdbcds with quoted or hdbcds naming
1824
+ // hdbcds with quoted or hdbcds naming
1741
1825
  return env.namePrefix + quoteId(getRealName(csn, artifactName).replace(/\./g, '_'));
1742
1826
  }
1743
1827
 
@@ -70,22 +70,19 @@ function toRenameDdl(csn, options) {
70
70
 
71
71
  resultStr += Object.keys(art.elements).map((name) => {
72
72
  const e = art.elements[name];
73
- let result = '';
73
+ let str = '';
74
74
 
75
75
  const beforeColumnName = quoteSqlId(name);
76
76
  const afterColumnName = plainSqlId(name);
77
77
 
78
78
  if (!e._ignore) {
79
- if (e.target) {
80
- resultStr += ' ';
81
- result = ` EXEC 'ALTER TABLE ${afterTableName} DROP ASSOCIATION ${beforeColumnName}';\n`;
82
- }
83
- else if (beforeColumnName !== afterColumnName) {
84
- resultStr += ' ';
85
- result = ` EXEC 'RENAME COLUMN ${afterTableName}.${beforeColumnName} TO ${afterColumnName}';\n`;
86
- }
79
+ if (e.target)
80
+ str = ` EXEC 'ALTER TABLE ${afterTableName} DROP ASSOCIATION ${beforeColumnName}';\n`;
81
+
82
+ else if (beforeColumnName !== afterColumnName)
83
+ str = ` EXEC 'RENAME COLUMN ${afterTableName}.${beforeColumnName} TO ${afterColumnName}';\n`;
87
84
  }
88
- return result;
85
+ return str;
89
86
  }).join('');
90
87
  }
91
88
  return resultStr;