@sap/cds-compiler 3.6.2 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +3 -0
  3. package/bin/cdsc.js +9 -5
  4. package/doc/CHANGELOG_BETA.md +20 -2
  5. package/doc/CHANGELOG_DEPRECATED.md +2 -2
  6. package/lib/api/main.js +2 -1
  7. package/lib/base/dictionaries.js +10 -0
  8. package/lib/base/message-registry.js +56 -12
  9. package/lib/base/messages.js +39 -20
  10. package/lib/base/model.js +1 -0
  11. package/lib/base/shuffle.js +2 -1
  12. package/lib/checks/elements.js +29 -1
  13. package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +9 -5
  14. package/lib/checks/nonexpandableStructured.js +1 -1
  15. package/lib/checks/onConditions.js +8 -5
  16. package/lib/checks/types.js +6 -1
  17. package/lib/checks/validator.js +7 -3
  18. package/lib/compiler/assert-consistency.js +20 -23
  19. package/lib/compiler/base.js +1 -2
  20. package/lib/compiler/builtins.js +2 -2
  21. package/lib/compiler/checks.js +237 -242
  22. package/lib/compiler/define.js +63 -75
  23. package/lib/compiler/extend.js +325 -22
  24. package/lib/compiler/finalize-parse-cdl.js +1 -55
  25. package/lib/compiler/kick-start.js +6 -7
  26. package/lib/compiler/populate.js +284 -288
  27. package/lib/compiler/propagator.js +15 -13
  28. package/lib/compiler/resolve.js +136 -306
  29. package/lib/compiler/shared.js +42 -44
  30. package/lib/compiler/tweak-assocs.js +29 -27
  31. package/lib/compiler/utils.js +29 -3
  32. package/lib/edm/annotations/genericTranslation.js +7 -13
  33. package/lib/edm/annotations/preprocessAnnotations.js +3 -0
  34. package/lib/edm/csn2edm.js +0 -4
  35. package/lib/edm/edm.js +6 -4
  36. package/lib/edm/edmAnnoPreprocessor.js +1 -0
  37. package/lib/edm/edmPreprocessor.js +1 -5
  38. package/lib/gen/Dictionary.json +34 -2
  39. package/lib/gen/language.checksum +1 -1
  40. package/lib/gen/language.interp +1 -1
  41. package/lib/gen/languageParser.js +2429 -2401
  42. package/lib/inspect/inspectPropagation.js +2 -0
  43. package/lib/json/from-csn.js +87 -41
  44. package/lib/json/to-csn.js +47 -16
  45. package/lib/language/errorStrategy.js +1 -0
  46. package/lib/language/genericAntlrParser.js +109 -28
  47. package/lib/language/language.g4 +20 -4
  48. package/lib/model/csnRefs.js +1 -1
  49. package/lib/model/csnUtils.js +1 -0
  50. package/lib/model/revealInternalProperties.js +1 -2
  51. package/lib/modelCompare/compare.js +2 -1
  52. package/lib/render/manageConstraints.js +5 -2
  53. package/lib/render/toCdl.js +20 -7
  54. package/lib/render/toHdbcds.js +2 -8
  55. package/lib/render/toSql.js +4 -3
  56. package/lib/render/utils/common.js +9 -5
  57. package/lib/transform/db/assertUnique.js +2 -1
  58. package/lib/transform/db/expansion.js +2 -0
  59. package/lib/transform/db/flattening.js +37 -36
  60. package/lib/transform/db/rewriteCalculatedElements.js +559 -0
  61. package/lib/transform/db/transformExists.js +4 -0
  62. package/lib/transform/db/views.js +40 -37
  63. package/lib/transform/forRelationalDB.js +38 -28
  64. package/lib/transform/odata/typesExposure.js +50 -15
  65. package/lib/transform/parseExpr.js +14 -8
  66. package/lib/transform/transformUtilsNew.js +6 -5
  67. package/lib/transform/translateAssocsToJoins.js +49 -33
  68. package/package.json +1 -1
@@ -83,13 +83,16 @@ function validateOnCondition( member, memberName, property, path ) {
83
83
  if (_links[j].art.target && !((_links[j].art === member) || ref[j] === '$self' || ref[j] === '$projection' || (validDollarSelf && j === _links.length - 1))) {
84
84
  if (_links[j].art.on) {
85
85
  // It's an unmanaged association - traversal is always forbidden
86
- this.error(null, csnPath, { id, elemref }, 'ON-conditions can\'t follow unmanaged associations, step $(ID) of path $(ELEMREF)');
86
+ this.error('ref-unexpected-navigation', csnPath, { '#': 'unmanaged', id, elemref });
87
87
  }
88
88
  else {
89
89
  // It's a managed association - access of the foreign keys is allowed
90
90
  const nextRef = ref[j + 1].id || ref[j + 1];
91
- if (!_links[j].art.keys.some(r => r.ref[0] === nextRef))
92
- this.error(null, csnPath, { id, elemref }, 'ON-conditions can only follow managed associations to the foreign keys of the managed association, step $(ID) of path $(ELEMREF)');
91
+ if (!_links[j].art.keys.some(r => r.ref[0] === nextRef)) {
92
+ this.error('ref-unexpected-navigation', csnPath, {
93
+ '#': 'std', id, elemref, name: nextRef,
94
+ });
95
+ }
93
96
  }
94
97
  }
95
98
 
@@ -113,8 +116,8 @@ function validateOnCondition( member, memberName, property, path ) {
113
116
  // 2) Path ends on an association (managed or unmanaged) and the other operand is a '$self'
114
117
 
115
118
  // If this path ends structured or on an association, perform the check:
116
- if ((type.target) &&
117
- !( /* 1) */ (type.target && type.keys) && validStructuredElement ||
119
+ if ((type.target || type.elements) &&
120
+ !( /* 1) */ (type.target && type.keys || type.elements) && validStructuredElement ||
118
121
  /* 2) */ (type.target && validDollarSelf)) &&
119
122
  !type.virtual) {
120
123
  // Do nothing - handled by lib/checks/nonexpandableStructured.js
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { hasAnnotationValue } = require('../model/csnUtils');
4
+ const { isBetaEnabled } = require('../base/model');
4
5
 
5
6
  // Only to be used with validator.js - a correct this value needs to be provided!
6
7
 
@@ -51,7 +52,11 @@ function checkElementTypeDefinitionHasType( member, memberName, prop, path ) {
51
52
  // Computed elements, e.g. "1+1 as foo" in a view don't have a valid type and
52
53
  // are skipped here. References to such columns are checked further below.
53
54
  const parent = this.csn.definitions[path[1]];
54
- if (!parent.projection && !parent.query && !hasArtifactTypeInformation(member)) {
55
+
56
+ // should only happen with csn input, not in cdl
57
+ // calculated elements may not have a .type (requires beta flag)
58
+ if ((!member.value || !isBetaEnabled(this.options, 'calculatedElements')) &&
59
+ !parent.projection && !parent.query && !hasArtifactTypeInformation(member)) {
55
60
  errorAboutMissingType(this.error, path, memberName, true);
56
61
  return;
57
62
  }
@@ -12,7 +12,7 @@ const { validateSelectItems } = require('./selectItems');
12
12
  const { rejectParamDefaultsInHanaCds, warnAboutDefaultOnAssociationForHanaCds } = require('./defaultValues');
13
13
  const validateCdsPersistenceAnnotation = require('./cdsPersistence');
14
14
  const checkUsedTypesForAnonymousAspectComposition = require('./managedInType');
15
- const checkForEmptyOrOnlyVirtual = require('./emptyOrOnlyVirtual');
15
+ const validateHasPersistedElements = require('./hasPersistedElements');
16
16
  const checkForHanaTypes = require('./checkForTypes');
17
17
  const checkForParams = require('./parameters');
18
18
  // forOdata
@@ -30,7 +30,8 @@ const {
30
30
  checkTypeIsScalar, checkDecimalScale,
31
31
  } = require('./types');
32
32
  const {
33
- checkPrimaryKey, checkVirtualElement, checkManagedAssoc, checkRecursiveTypeUsage,
33
+ checkPrimaryKey, checkVirtualElement, checkManagedAssoc,
34
+ checkRecursiveTypeUsage, rejectAnnotationsOnCalcElement,
34
35
  } = require('./elements');
35
36
  const checkForInvalidTarget = require('./invalidTarget');
36
37
  const { validateAssociationsInItems } = require('./arrayOfs');
@@ -54,6 +55,8 @@ const forRelationalDBMemberValidators
54
55
  warnAboutDefaultOnAssociationForHanaCds,
55
56
  // sql.prepend/append
56
57
  checkSqlAnnotationOnElement,
58
+ // no temporal annotations on calc elements
59
+ rejectAnnotationsOnCalcElement,
57
60
  ];
58
61
 
59
62
  const forRelationalDBArtifactValidators
@@ -61,7 +64,7 @@ const forRelationalDBArtifactValidators
61
64
  // @cds.persistence has no impact on odata
62
65
  validateCdsPersistenceAnnotation,
63
66
  // virtual items are not persisted on the db
64
- checkForEmptyOrOnlyVirtual,
67
+ validateHasPersistedElements,
65
68
  // sql.prepend/append
66
69
  checkSqlAnnotationOnArtifact,
67
70
  ];
@@ -254,6 +257,7 @@ function forOdata( csn, that ) {
254
257
  }
255
258
  }
256
259
  ),
260
+ // eslint-disable-next-line sonarjs/no-empty-collection
257
261
  forOdataQueryValidators.concat(commonQueryValidators),
258
262
  {
259
263
  skipArtifact: this.isExternalServiceMember,
@@ -72,7 +72,7 @@ const { locationString, hasErrors } = require('../base/messages');
72
72
  // Properties that can appear where a type can have type arguments.
73
73
  const typeProperties = [
74
74
  'type', '$typeArgs', 'length', 'precision', 'scale', 'srid',
75
- '_effectiveType',
75
+ '_effectiveType', '$effectiveSeqNo',
76
76
  ];
77
77
 
78
78
  class InternalConsistencyError extends Error {
@@ -191,8 +191,8 @@ function assertConsistency( model, stage ) {
191
191
  test: isDictionary( definition ),
192
192
  requires: [ 'kind', 'name' ],
193
193
  optional: [
194
- 'elements', '$autoElement', '$uncheckedElements',
195
- '$requireElementAccess', '_effectiveType', '_deps',
194
+ 'elements', '$autoElement', '$uncheckedElements', '_origin',
195
+ '$requireElementAccess', '_effectiveType', '$effectiveSeqNo', '_deps',
196
196
  ],
197
197
  schema: {
198
198
  kind: { test: isString, enum: [ 'builtin' ] },
@@ -250,18 +250,17 @@ function assertConsistency( model, stage ) {
250
250
  schema: { args: { inherits: 'query', test: isArray( query ) } },
251
251
  requires: [ 'op', 'location', 'args' ],
252
252
  optional: [
253
- 'quantifier', 'orderBy', 'limit', '_leadingQuery',
254
- 'name', '$parens', 'kind', '_parent', '_main', '_effectiveType', // in FROM
253
+ 'quantifier', 'orderBy', 'limit', 'name', '$parens', 'kind',
254
+ '_parent', '_main', '_leadingQuery', '_effectiveType', '$effectiveSeqNo', // in FROM
255
255
  ],
256
256
  },
257
257
  select: { // sub query
258
258
  requires: [ 'op', 'location', 'from' ],
259
259
  optional: [
260
260
  'name', '$parens', 'quantifier', 'mixin', 'excludingDict', 'columns', 'elements', '_deps',
261
- 'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit',
262
- '_projections', '_block', '_parent', '_main', '_effectiveType', '$expand',
261
+ 'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit', '_origin', '_block',
262
+ '_projections', '_parent', '_main', '_effectiveType', '$effectiveSeqNo', '$expand',
263
263
  '$tableAliases', 'kind', '_$next', '_combined', '$inlines', '_status',
264
- '_extension', // for unapplied extensions
265
264
  ],
266
265
  },
267
266
  none: { optional: () => true }, // parse error
@@ -285,7 +284,7 @@ function assertConsistency( model, stage ) {
285
284
  'elements', '_origin', '_joinParent', '$joinArgsIndex', '$syntax',
286
285
  '$parens', '_status', // TODO: only in from
287
286
  'scope', '_artifact', '$inferred', 'kind',
288
- '_effectiveType', // TODO:check this
287
+ '_effectiveType', '$effectiveSeqNo', // TODO:check this
289
288
  '$duplicates', // In JOIN if both sides are the same.
290
289
  ],
291
290
  },
@@ -293,8 +292,8 @@ function assertConsistency( model, stage ) {
293
292
  requires: [ 'query', 'location' ],
294
293
  optional: [
295
294
  '$parens',
296
- 'kind', 'name', '_block', '_parent', '_main',
297
- '_effectiveType', 'elements', '_origin', '_joinParent', '$joinArgsIndex',
295
+ 'kind', 'name', '_block', '_parent', '_main', 'elements',
296
+ '_effectiveType', '$effectiveSeqNo', '_origin', '_joinParent', '$joinArgsIndex',
298
297
  '$duplicates', // duplicate query in FROM clause
299
298
  ],
300
299
  },
@@ -340,7 +339,7 @@ function assertConsistency( model, stage ) {
340
339
  optional: [
341
340
  'path', 'elements', '_outer', '_parent', '_main', '_block', 'kind',
342
341
  'scope', '_artifact', '$inferred', '$expand', '$inCycle', '$tableAliases', '_$next',
343
- '_effectiveType', // by propagation
342
+ '_origin', '_effectiveType', '$effectiveSeqNo',
344
343
  ],
345
344
  },
346
345
  target: {
@@ -373,7 +372,7 @@ function assertConsistency( model, stage ) {
373
372
  // required to be set by Core Compiler even with parse errors
374
373
  test: isString,
375
374
  enum: [
376
- 'context', 'service', 'entity', 'type', 'aspect', 'const', 'annotation',
375
+ 'context', 'service', 'entity', 'type', 'aspect', 'annotation',
377
376
  'element', 'enum', 'action', 'function', 'param', 'key', 'event',
378
377
  'annotate', 'extend', '$column',
379
378
  'select', '$join', 'mixin',
@@ -393,10 +392,8 @@ function assertConsistency( model, stage ) {
393
392
  optional: [
394
393
  'location', '$inferred', 'sort', 'nulls',
395
394
  'param', 'scope', // for dynamic parameter '?'
396
- // through cast() with enum through CSN->XSN
397
- // TODO: re-check #9225, this should be directly in the query element,
398
- // not inside value, no `enum` inside `cast`!
399
- 'elements', 'items', 'enum', '$expand', 'target',
395
+ // A2J wrongly propagates the following into a CAST of the CSN passed to compileX:
396
+ 'elements', 'items', 'enum',
400
397
  ],
401
398
 
402
399
  kind: true,
@@ -515,7 +512,7 @@ function assertConsistency( model, stage ) {
515
512
  optional: [
516
513
  'enum',
517
514
  'elements', 'cardinality', 'target', 'on', 'foreignKeys', 'items',
518
- '_outer', '_effectiveType', 'notNull', '_parent',
515
+ '_outer', '_effectiveType', '$effectiveSeqNo', 'notNull', '_parent',
519
516
  '_origin', '_block', '$inferred', '$expand', '$inCycle', '_deps',
520
517
  '$syntax',
521
518
  '_status', '_redirected',
@@ -550,6 +547,7 @@ function assertConsistency( model, stage ) {
550
547
  _artifact: { test: TODO },
551
548
  _navigation: { test: TODO },
552
549
  _effectiveType: { kind: true, test: TODO },
550
+ $effectiveSeqNo: { kind: true, test: isNumber },
553
551
  _joinParent: { test: TODO },
554
552
  $joinArgsIndex: { test: isNumber },
555
553
  _outer: { test: TODO }, // for returns/items
@@ -565,20 +563,19 @@ function assertConsistency( model, stage ) {
565
563
  '$tableAliases', '$inlines',
566
564
  ],
567
565
  optional: [
568
- '_effectiveType', '$parens',
566
+ '_effectiveType', '$effectiveSeqNo', '$parens',
569
567
  '_deps', '$expand',
570
568
  // query specific
571
569
  'where', 'columns', 'mixin', 'quantifier', 'offset',
572
570
  'orderBy', '$orderBy', 'groupBy', 'excludingDict', 'having',
573
- 'limit', '_status',
574
- '_extension', // for unapplied extensions
571
+ 'limit', '_status', '_origin', '_effectiveType', '$effectiveSeqNo',
575
572
  ],
576
573
  },
577
574
  _leadingQuery: { kind: true, test: TODO },
578
575
  $replacement: { kind: true, test: TODO }, // for smart * in queries
579
- _origin: { kind: [ 'entity' ], test: TODO },
576
+ _origin: { kind: true, test: TODO },
580
577
  _pathHead: { kind: [ 'element', undefined ], test: TODO }, // column or * (wildcard)
581
- _from: { kind: true, test: TODO }, // all table refs necessary to compute elements
578
+ _from: { kind: true, test: TODO }, // TODO: not necessary anymore ?
582
579
  // array of $tableAlias (or includes) for explicit and implicit redirection:
583
580
  _redirected: { kind: true, test: TODO },
584
581
  // ...array of table aliases for targets from orig to new
@@ -43,14 +43,13 @@ const kindProperties = {
43
43
  source: { artifacts: true }, // TODO -> $source
44
44
  using: {},
45
45
  extend: {
46
- isExtension: true,
47
46
  noDep: 'special',
48
47
  elements: true, /* only for parse-cdl */
49
48
  actions: true, /* only for parse-cdl */
50
49
  enum: true, /* only for parse-cdl */
51
50
  },
52
51
  annotate: {
53
- isExtension: true, noDep: 'special', elements: true, enum: true, actions: true, params: true,
52
+ noDep: 'special', elements: true, enum: true, actions: true, params: true,
54
53
  },
55
54
  builtin: {}, // = CURRENT_DATE, TODO: improve
56
55
  $parameters: {}, // $parameters in query entities
@@ -447,11 +447,11 @@ function initBuiltins( model ) {
447
447
  const absolute = prefix + name;
448
448
  // TODO: reconsider whether to set a type to itself - looks wrong
449
449
  const art = {
450
- kind: 'type', builtin: true, name: { absolute }, type: { path: [ { id: absolute } ] },
450
+ kind: 'type', builtin: true, name: { absolute },
451
451
  };
452
- setProp( art.type, '_artifact', art );
453
452
  if (parent)
454
453
  parent._subArtifacts[name] = art;
454
+ setProp( art, '_origin', '' );
455
455
  setProp( art, '_effectiveType', art );
456
456
  setProp( art, '_deps', [] );
457
457
  Object.assign( art, builtins[name] );