@sap/cds-compiler 2.10.4 → 2.11.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 (70) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/bin/cdsc.js +42 -25
  3. package/bin/cdsse.js +1 -0
  4. package/doc/CHANGELOG_BETA.md +4 -0
  5. package/lib/api/.eslintrc.json +2 -0
  6. package/lib/api/main.js +9 -23
  7. package/lib/api/options.js +12 -4
  8. package/lib/api/validate.js +23 -2
  9. package/lib/backends.js +9 -8
  10. package/lib/base/dictionaries.js +2 -1
  11. package/lib/base/message-registry.js +10 -2
  12. package/lib/base/messages.js +23 -9
  13. package/lib/base/model.js +5 -4
  14. package/lib/base/optionProcessorHelper.js +56 -22
  15. package/lib/checks/selectItems.js +4 -0
  16. package/lib/checks/unknownMagic.js +6 -3
  17. package/lib/compiler/assert-consistency.js +7 -0
  18. package/lib/compiler/base.js +65 -0
  19. package/lib/compiler/builtins.js +28 -1
  20. package/lib/compiler/checks.js +2 -1
  21. package/lib/compiler/definer.js +58 -91
  22. package/lib/compiler/index.js +16 -4
  23. package/lib/compiler/propagator.js +5 -2
  24. package/lib/compiler/resolver.js +93 -34
  25. package/lib/compiler/shared.js +29 -202
  26. package/lib/compiler/utils.js +173 -0
  27. package/lib/edm/annotations/genericTranslation.js +1 -1
  28. package/lib/edm/csn2edm.js +3 -2
  29. package/lib/edm/edmPreprocessor.js +31 -36
  30. package/lib/edm/edmUtils.js +3 -3
  31. package/lib/gen/language.checksum +1 -1
  32. package/lib/gen/language.interp +17 -1
  33. package/lib/gen/language.tokens +79 -73
  34. package/lib/gen/languageLexer.interp +19 -1
  35. package/lib/gen/languageLexer.js +779 -731
  36. package/lib/gen/languageLexer.tokens +71 -65
  37. package/lib/gen/languageParser.js +4668 -4072
  38. package/lib/json/from-csn.js +10 -10
  39. package/lib/json/to-csn.js +169 -34
  40. package/lib/language/antlrParser.js +11 -0
  41. package/lib/language/genericAntlrParser.js +72 -14
  42. package/lib/language/language.g4 +73 -0
  43. package/lib/main.d.ts +136 -17
  44. package/lib/main.js +3 -1
  45. package/lib/model/api.js +2 -2
  46. package/lib/model/csnRefs.js +108 -31
  47. package/lib/model/csnUtils.js +63 -29
  48. package/lib/model/enrichCsn.js +36 -9
  49. package/lib/model/revealInternalProperties.js +20 -4
  50. package/lib/modelCompare/compare.js +2 -1
  51. package/lib/optionProcessor.js +29 -18
  52. package/lib/render/DuplicateChecker.js +1 -1
  53. package/lib/render/toCdl.js +9 -3
  54. package/lib/render/toHdbcds.js +16 -36
  55. package/lib/render/toSql.js +23 -5
  56. package/lib/transform/db/constraints.js +278 -119
  57. package/lib/transform/db/draft.js +3 -2
  58. package/lib/transform/db/expansion.js +6 -4
  59. package/lib/transform/db/flattening.js +17 -1
  60. package/lib/transform/db/transformExists.js +61 -2
  61. package/lib/transform/db/views.js +438 -0
  62. package/lib/transform/forHanaNew.js +56 -435
  63. package/lib/transform/forOdataNew.js +9 -2
  64. package/lib/transform/localized.js +2 -0
  65. package/lib/transform/transformUtilsNew.js +10 -0
  66. package/lib/transform/translateAssocsToJoins.js +5 -13
  67. package/lib/utils/file.js +5 -3
  68. package/lib/utils/term.js +65 -42
  69. package/lib/utils/timetrace.js +48 -26
  70. package/package.json +1 -1
@@ -3,7 +3,7 @@
3
3
  const {
4
4
  getParentNameOf, getLastPartOf, getLastPartOfRef,
5
5
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
6
- getRootArtifactName, getResultingName, getNamespace, forEachMember,
6
+ getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement,
7
7
  } = require('../model/csnUtils');
8
8
  const keywords = require('../base/keywords');
9
9
  const {
@@ -17,7 +17,7 @@ const DuplicateChecker = require('./DuplicateChecker');
17
17
  const { isDeprecatedEnabled, forEachDefinition } = require('../base/model');
18
18
  const { checkCSNVersion } = require('../json/csnVersion');
19
19
  const { makeMessageFunction } = require('../base/messages');
20
- const timetrace = require('../utils/timetrace');
20
+ const { timetrace } = require('../utils/timetrace');
21
21
 
22
22
  const { smartId, delimitedId } = require('../sql-identifier');
23
23
 
@@ -558,7 +558,7 @@ function toHdbcdsSource(csn, options) {
558
558
  result += env.indent + (elm.key && !isSubElement ? 'key ' : '') +
559
559
  (elm.masked ? 'masked ' : '') +
560
560
  quotedElementName + (omitColon ? ' ' : ' : ') +
561
- renderTypeReference(elm, env, undefined) +
561
+ renderTypeReference(elm, env) +
562
562
  renderNullability(elm);
563
563
  if (elm.default)
564
564
  result += ` default ${renderExpr(elm.default, env)}`;
@@ -680,7 +680,7 @@ function toHdbcdsSource(csn, options) {
680
680
  */
681
681
  function renderViewColumn(col, env, element) {
682
682
  // Annotations and column
683
- let result = element && hasHanaComment(element, options) ? `${env.indent}@Comment: '${getEscapedHanaComment(element)}'\n` : '';
683
+ let result = '';
684
684
 
685
685
  const leaf = col.as || col.ref && col.ref[col.ref.length - 1];
686
686
  // Render 'null as <alias>' only for database and if element is virtual
@@ -959,7 +959,7 @@ function toHdbcdsSource(csn, options) {
959
959
  }
960
960
  else {
961
961
  // Derived type or annotation with non-anonymous type
962
- result += ` : ${renderTypeReference(art, env, false)};\n`;
962
+ result += ` : ${renderTypeReference(art, env)};\n`;
963
963
  }
964
964
  return result;
965
965
  }
@@ -970,10 +970,9 @@ function toHdbcdsSource(csn, options) {
970
970
  *
971
971
  * @param {CSN.Element} elm Element using the type reference
972
972
  * @param {CdlRenderEnvironment} env Environment
973
- * @param {boolean} [noEnum=false] If true, do not render enums
974
973
  * @returns {string} Rendered type reference
975
974
  */
976
- function renderTypeReference(elm, env, noEnum = false) {
975
+ function renderTypeReference(elm, env) {
977
976
  let result = '';
978
977
 
979
978
  // Array type: Render items instead
@@ -1011,11 +1010,7 @@ function toHdbcdsSource(csn, options) {
1011
1010
  // Reference to another element
1012
1011
  if (elm.type.ref) {
1013
1012
  // For HANA CDS, we need a 'type of'
1014
- let result = `type of ${renderAbsolutePath(elm.type, env)}`;
1015
- if (elm.enum)
1016
- result += renderEnum(elm.enum, env);
1017
-
1018
- return result;
1013
+ return `type of ${renderAbsolutePath(elm.type, env)}`;
1019
1014
  }
1020
1015
 
1021
1016
  // If we get here, it must be a named type
@@ -1027,8 +1022,6 @@ function toHdbcdsSource(csn, options) {
1027
1022
  // Type names are never flattened (derived types are unraveled in HANA)
1028
1023
  result += renderAbsoluteNameWithQuotes(elm.type, env);
1029
1024
  }
1030
- if (elm.enum && !noEnum)
1031
- result += renderEnum(elm.enum, env);
1032
1025
 
1033
1026
  return result;
1034
1027
  }
@@ -1094,27 +1087,6 @@ function toHdbcdsSource(csn, options) {
1094
1087
  return elm.type.replace(/^cds\./, '') + renderTypeParameters(elm);
1095
1088
  }
1096
1089
 
1097
- /**
1098
- * Render the 'enum { ... } part of a type declaration
1099
- *
1100
- * @param {CSN.EnumElements} enumPart Enum part of a type declaration
1101
- * @param {CdlRenderEnvironment} env Environment
1102
- * @returns {string} Rendered enum
1103
- */
1104
- function renderEnum(enumPart, env) {
1105
- let result = ' enum {\n';
1106
- const childEnv = increaseIndent(env);
1107
- for (const name in enumPart) {
1108
- const enumConst = enumPart[name];
1109
- result += childEnv.indent + quoteId(name);
1110
- if (enumConst.val !== undefined)
1111
- result += ` = ${renderExpr(enumConst, childEnv)}`;
1112
- result += ';\n';
1113
- }
1114
- result += `${env.indent}}`;
1115
- return result;
1116
- }
1117
-
1118
1090
  /**
1119
1091
  * Render an expression (including paths and values) or condition 'x'.
1120
1092
  * (no trailing LF, don't indent if inline)
@@ -1229,7 +1201,12 @@ function toHdbcdsSource(csn, options) {
1229
1201
  */
1230
1202
  function renderExpressionRef(x) {
1231
1203
  if (!x.param && !x.global) {
1204
+ const magicReplacement = getVariableReplacement(x.ref, options);
1232
1205
  if (x.ref[0] === '$user') {
1206
+ if (magicReplacement !== null)
1207
+ return `'${magicReplacement}'`;
1208
+
1209
+ // Keep old way of solving this to remain backwards compatible
1233
1210
  // FIXME: this is all not enough: we might need an explicit select item alias
1234
1211
  if (x.ref[1] === 'id') {
1235
1212
  if (options.magicVars && options.magicVars.user && (typeof options.magicVars.user === 'string' || options.magicVars.user instanceof String))
@@ -1251,6 +1228,9 @@ function toHdbcdsSource(csn, options) {
1251
1228
  else if (x.ref[1] === 'to')
1252
1229
  return 'TO_TIMESTAMP(SESSION_CONTEXT(\'VALID-TO\'))';
1253
1230
  }
1231
+ else if (x.ref[0] === '$session' && magicReplacement !== null) {
1232
+ return `'${magicReplacement}'`;
1233
+ }
1254
1234
  }
1255
1235
  return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, x.ref)).join('.')}`;
1256
1236
  }
@@ -1262,7 +1242,7 @@ function toHdbcdsSource(csn, options) {
1262
1242
  * @returns {string} Rendered cast()
1263
1243
  */
1264
1244
  function renderExplicitTypeCast(value) {
1265
- let typeRef = renderTypeReference(x.cast, env, true);
1245
+ let typeRef = renderTypeReference(x.cast, env);
1266
1246
 
1267
1247
  // inside a cast expression, the cds and hana cds types need to be mapped to hana sql types
1268
1248
  const hanaSqlType = cdsToSqlTypes.hana[x.cast.type] || cdsToSqlTypes.standard[x.cast.type];
@@ -4,7 +4,7 @@
4
4
  const {
5
5
  getLastPartOf, getLastPartOfRef,
6
6
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
7
- forEachDefinition, getResultingName,
7
+ forEachDefinition, getResultingName, getVariableReplacement,
8
8
  } = require('../model/csnUtils');
9
9
  const {
10
10
  renderFunc, beautifyExprArray, cdsToSqlTypes, getHanaComment, hasHanaComment,
@@ -15,7 +15,7 @@ const {
15
15
  const DuplicateChecker = require('./DuplicateChecker');
16
16
  const { checkCSNVersion } = require('../json/csnVersion');
17
17
  const { makeMessageFunction } = require('../base/messages');
18
- const timetrace = require('../utils/timetrace');
18
+ const { timetrace } = require('../utils/timetrace');
19
19
  const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
20
20
  const { smartFuncId } = require('../sql-identifier');
21
21
  const { sortCsn } = require('../json/to-csn');
@@ -567,7 +567,7 @@ function toSqlDdl(csn, options) {
567
567
  if (options.toSql.dialect === 'hana')
568
568
  renderIndexesInto(art.technicalConfig && art.technicalConfig.hana.indexes, artifactName, resultObj, env);
569
569
 
570
- if (options.toSql.dialect === 'hana' && hasHanaComment(art, options, art))
570
+ if (options.toSql.dialect === 'hana' && hasHanaComment(art, options))
571
571
  result += ` COMMENT '${getHanaComment(art)}'`;
572
572
 
573
573
  resultObj.hdbtable[artifactName] = result;
@@ -1054,7 +1054,7 @@ function toSqlDdl(csn, options) {
1054
1054
  definitionsDuplicateChecker.addArtifact(art['@cds.persistence.name'], art && art.$location, artifactName);
1055
1055
  let result = `VIEW ${viewName}`;
1056
1056
 
1057
- if (options.toSql.dialect === 'hana' && hasHanaComment(art, options, art))
1057
+ if (options.toSql.dialect === 'hana' && hasHanaComment(art, options))
1058
1058
  result += ` COMMENT '${getHanaComment(art)}'`;
1059
1059
 
1060
1060
  result += renderParameterDefinitions(artifactName, art.params);
@@ -1383,6 +1383,8 @@ function toSqlDdl(csn, options) {
1383
1383
  // Function call, possibly with args (use '=>' for named args)
1384
1384
  else if (x.func) {
1385
1385
  const funcName = smartFuncId(prepareIdentifier(x.func), options.toSql.dialect);
1386
+ if (x.xpr)
1387
+ return renderWindowFunction(funcName, x, env);
1386
1388
  return renderFunc(funcName, x, options.toSql.dialect, a => renderArgs(a, '=>', env, null));
1387
1389
  }
1388
1390
  // Nested expression
@@ -1405,6 +1407,13 @@ function toSqlDdl(csn, options) {
1405
1407
  throw new Error(`Unknown expression: ${JSON.stringify(x)}`);
1406
1408
  }
1407
1409
 
1410
+ function renderWindowFunction(funcName, node, env) {
1411
+ const suffix = node.xpr.shift(); // OVER
1412
+ let r = `${funcName}(${renderArgs(node, '=>', env, null)})`;
1413
+ r += ` ${suffix} (${renderExpr(node.xpr, env)})`;
1414
+ return r;
1415
+ }
1416
+
1408
1417
  function renderExpressionLiteral(x) {
1409
1418
  // Literal value, possibly with explicit 'literal' property
1410
1419
  switch (x.literal || typeof x.val) {
@@ -1441,7 +1450,12 @@ function toSqlDdl(csn, options) {
1441
1450
 
1442
1451
  function renderExpressionRef(x) {
1443
1452
  if (!x.param && !x.global) {
1453
+ const magicReplacement = getVariableReplacement(x.ref, options);
1454
+
1444
1455
  if (x.ref[0] === '$user') {
1456
+ if (magicReplacement !== null)
1457
+ return `'${magicReplacement}'`;
1458
+
1445
1459
  const result = render$user(x);
1446
1460
  // Invalid second path step doesn't cause a return
1447
1461
  if (result)
@@ -1453,6 +1467,9 @@ function toSqlDdl(csn, options) {
1453
1467
  if (result)
1454
1468
  return result;
1455
1469
  }
1470
+ else if (x.ref[0] === '$session' && magicReplacement !== null) {
1471
+ return `'${magicReplacement}'`;
1472
+ }
1456
1473
  }
1457
1474
  // FIXME: We currently cannot distinguish whether '$parameters' was quoted or not - we
1458
1475
  // assume that it was not if the path has length 2 (
@@ -1475,6 +1492,7 @@ function toSqlDdl(csn, options) {
1475
1492
  function render$user(x) {
1476
1493
  // FIXME: this is all not enough: we might need an explicit select item alias
1477
1494
  if (x.ref[1] === 'id') {
1495
+ // Keep the old-style for compatibilty with magicVars.id - instead of magicVars.user.id...
1478
1496
  if (options.toSql.user && typeof options.toSql.user === 'string' || options.toSql.user instanceof String)
1479
1497
  return `'${options.toSql.user}'`;
1480
1498
 
@@ -1494,7 +1512,7 @@ function toSqlDdl(csn, options) {
1494
1512
  }
1495
1513
  return 'SESSION_CONTEXT(\'LOCALE\')';
1496
1514
  }
1497
- // Basically: Second path step was invalid, do nothing
1515
+ // Basically: Second path step was invalid, do nothing - should not happen, see 'unknownMagic.js'
1498
1516
  return null;
1499
1517
  }
1500
1518
  /**