@sap/cds-compiler 2.10.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 (103) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/bin/.eslintrc.json +1 -2
  3. package/bin/cds_update_identifiers.js +10 -8
  4. package/bin/cdsc.js +58 -35
  5. package/bin/cdsse.js +1 -0
  6. package/bin/cdsv2m.js +3 -2
  7. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  8. package/doc/CHANGELOG_BETA.md +16 -0
  9. package/lib/api/.eslintrc.json +2 -0
  10. package/lib/api/main.js +10 -36
  11. package/lib/api/options.js +17 -8
  12. package/lib/api/validate.js +30 -3
  13. package/lib/backends.js +12 -13
  14. package/lib/base/dictionaries.js +2 -1
  15. package/lib/base/keywords.js +3 -2
  16. package/lib/base/message-registry.js +64 -11
  17. package/lib/base/messages.js +38 -18
  18. package/lib/base/model.js +6 -4
  19. package/lib/base/optionProcessorHelper.js +148 -86
  20. package/lib/checks/.eslintrc.json +2 -0
  21. package/lib/checks/actionsFunctions.js +2 -1
  22. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  23. package/lib/checks/foreignKeys.js +4 -4
  24. package/lib/checks/managedInType.js +4 -4
  25. package/lib/checks/queryNoDbArtifacts.js +1 -3
  26. package/lib/checks/selectItems.js +4 -0
  27. package/lib/checks/sql-snippets.js +93 -0
  28. package/lib/checks/unknownMagic.js +6 -3
  29. package/lib/checks/validator.js +8 -0
  30. package/lib/compiler/assert-consistency.js +14 -5
  31. package/lib/compiler/base.js +64 -0
  32. package/lib/compiler/builtins.js +62 -16
  33. package/lib/compiler/checks.js +34 -10
  34. package/lib/compiler/definer.js +91 -112
  35. package/lib/compiler/index.js +30 -30
  36. package/lib/compiler/propagator.js +8 -4
  37. package/lib/compiler/resolver.js +279 -63
  38. package/lib/compiler/shared.js +65 -230
  39. package/lib/compiler/utils.js +191 -0
  40. package/lib/edm/annotations/genericTranslation.js +35 -18
  41. package/lib/edm/annotations/preprocessAnnotations.js +1 -1
  42. package/lib/edm/csn2edm.js +4 -3
  43. package/lib/edm/edm.js +8 -8
  44. package/lib/edm/edmPreprocessor.js +61 -59
  45. package/lib/edm/edmUtils.js +14 -15
  46. package/lib/gen/Dictionary.json +82 -40
  47. package/lib/gen/language.checksum +1 -1
  48. package/lib/gen/language.interp +19 -1
  49. package/lib/gen/language.tokens +80 -73
  50. package/lib/gen/languageLexer.interp +27 -1
  51. package/lib/gen/languageLexer.js +925 -826
  52. package/lib/gen/languageLexer.tokens +72 -65
  53. package/lib/gen/languageParser.js +4817 -4102
  54. package/lib/json/from-csn.js +57 -26
  55. package/lib/json/to-csn.js +244 -51
  56. package/lib/language/antlrParser.js +12 -1
  57. package/lib/language/docCommentParser.js +1 -1
  58. package/lib/language/errorStrategy.js +26 -8
  59. package/lib/language/genericAntlrParser.js +106 -30
  60. package/lib/language/language.g4 +200 -70
  61. package/lib/language/multiLineStringParser.js +536 -0
  62. package/lib/main.d.ts +220 -21
  63. package/lib/main.js +6 -3
  64. package/lib/model/api.js +2 -2
  65. package/lib/model/csnRefs.js +218 -86
  66. package/lib/model/csnUtils.js +99 -178
  67. package/lib/model/enrichCsn.js +84 -43
  68. package/lib/model/revealInternalProperties.js +25 -8
  69. package/lib/model/sortViews.js +8 -1
  70. package/lib/modelCompare/compare.js +2 -1
  71. package/lib/optionProcessor.js +33 -18
  72. package/lib/render/.eslintrc.json +1 -2
  73. package/lib/render/DuplicateChecker.js +2 -2
  74. package/lib/render/manageConstraints.js +1 -1
  75. package/lib/render/toCdl.js +202 -82
  76. package/lib/render/toHdbcds.js +194 -135
  77. package/lib/render/toRename.js +7 -10
  78. package/lib/render/toSql.js +91 -51
  79. package/lib/render/utils/common.js +24 -5
  80. package/lib/render/utils/sql.js +6 -4
  81. package/lib/transform/braceExpression.js +4 -2
  82. package/lib/transform/db/applyTransformations.js +189 -0
  83. package/lib/transform/db/associations.js +389 -0
  84. package/lib/transform/db/cdsPersistence.js +150 -0
  85. package/lib/transform/db/constraints.js +275 -119
  86. package/lib/transform/db/draft.js +6 -4
  87. package/lib/transform/db/expansion.js +10 -9
  88. package/lib/transform/db/flattening.js +23 -8
  89. package/lib/transform/db/temporal.js +236 -0
  90. package/lib/transform/db/transformExists.js +106 -25
  91. package/lib/transform/db/views.js +485 -0
  92. package/lib/transform/forHanaNew.js +90 -1036
  93. package/lib/transform/forOdataNew.js +11 -3
  94. package/lib/transform/localized.js +5 -14
  95. package/lib/transform/odata/generateForeignKeyElements.js +2 -2
  96. package/lib/transform/transformUtilsNew.js +34 -20
  97. package/lib/transform/translateAssocsToJoins.js +15 -23
  98. package/lib/transform/universalCsnEnricher.js +217 -47
  99. package/lib/utils/file.js +13 -6
  100. package/lib/utils/term.js +65 -42
  101. package/lib/utils/timetrace.js +55 -27
  102. package/package.json +1 -1
  103. package/lib/transform/db/helpers.js +0 -58
@@ -22,7 +22,7 @@ const { flattenCSN } = require('./odata/structureFlattener');
22
22
  const generateForeignKeys = require('./odata/generateForeignKeyElements');
23
23
  const expandStructKeysInAssociations = require('./odata/expandStructKeysInAssociations');
24
24
  const expandToFinalBaseType = require('./odata/toFinalBaseType');
25
- const timetrace = require('../utils/timetrace');
25
+ const { timetrace } = require('../utils/timetrace');
26
26
  const { attachPath } = require('./odata/attachPath');
27
27
  const enrichUniversalCsn = require('./universalCsnEnricher');
28
28
 
@@ -192,6 +192,10 @@ function transform4odataWithCsn(inputModel, options) {
192
192
 
193
193
  // Apply default type facets as set by options
194
194
  // Flatten on-conditions in unmanaged associations
195
+ /* FIXME (HJB): Is this comment still correct? processOnCond only strips $self
196
+ We should not remove $self prefixes in structured OData to not
197
+ interfer with path resolution
198
+ */
195
199
  // This must be done before all the draft logic as all
196
200
  // composition targets are annotated with @odata.draft.enabled in this step
197
201
  forEachDefinition(csn, [ setDefaultTypeFacets, processOnCond ], { skipArtifact: isExternalServiceMember });
@@ -299,8 +303,9 @@ function transform4odataWithCsn(inputModel, options) {
299
303
  // If @Core.Computed is explicitly set, don't overwrite it!
300
304
  if (node['@Core.Computed'] !== undefined) return;
301
305
 
302
- // For @odata.on.insert/update, also add @Core.Computed
303
- if (node['@odata.on.insert'] || node['@odata.on.update'])
306
+ // For @odata.on.insert/update, also add @Core.Computed
307
+ // @odata.on is deprecated, use @cds.on {update|insert} instead
308
+ if(['@odata.on.insert', '@odata.on.update', '@cds.on.insert', '@cds.on.update'].some(a => node[a]))
304
309
  node['@Core.Computed'] = true;
305
310
  }
306
311
 
@@ -569,6 +574,9 @@ function transform4odataWithCsn(inputModel, options) {
569
574
  // CDXCORE-481
570
575
  // (4.5) If the member is an association whose target has @cds.odata.valuelist annotate it
571
576
  // with @Common.ValueList.viaAssociation.
577
+ /*
578
+ FIXME (HJB): Comment outdated: Anno propagation to FKs is done in EdmPreprocessor
579
+ */
572
580
  // This must be done before foreign keys are calculated and the annotations are propagated
573
581
  // to them. This will make sure that association and all its foreign keys are annotated with
574
582
  // Common.ValueList in the final EDM.
@@ -5,14 +5,12 @@ const { setProp } = require('../base/model');
5
5
  const { hasErrors } = require('../base/messages');
6
6
  const { cloneCsnDictionary } = require('../model/csnUtils');
7
7
  const { cleanSymbols } = require('../base/cleanSymbols.js');
8
- const { rejectManagedAssociationsAndStructuresForHdbcsNames } = require('../checks/selectItems');
9
8
  const {
10
9
  cloneCsn,
11
10
  forEachDefinition,
12
11
  forEachGeneric,
13
12
  forAllQueries,
14
13
  sortCsnDefinitionsForTests,
15
- getUtils,
16
14
  } = require('../model/csnUtils');
17
15
 
18
16
  /**
@@ -79,7 +77,7 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
79
77
  if (hasExistingLocalizationViews(csn, options))
80
78
  return csn;
81
79
 
82
- const { info, error } = makeMessageFunction(csn, options);
80
+ const { info } = makeMessageFunction(csn, options);
83
81
 
84
82
  const noCoalesce = (options.localizedLanguageFallback === 'none' ||
85
83
  options.localizedWithoutCoalesce);
@@ -87,16 +85,7 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
87
85
  createDirectConvenienceViews(); // 1
88
86
  createTransitiveConvenienceViews(); // 2 + 3
89
87
 
90
- forEachDefinition(csn, (definition, artName, prop, path) => {
91
- cleanSymbols(definition, _hasLocalizedView, _isViewForEntity, _isViewForView, _targetFor)
92
- if(definition.query) {
93
- // reject managed association and structure publishing for to-hdbcds.hdbcds
94
- const that = { csnUtils: getUtils(csn), options, error };
95
- rejectManagedAssociationsAndStructuresForHdbcsNames.call(that, definition, path)
96
- }
97
- });
98
-
99
-
88
+ forEachDefinition(csn, definition => cleanSymbols(definition, _hasLocalizedView, _isViewForEntity, _isViewForView, _targetFor));
100
89
 
101
90
  sortCsnDefinitionsForTests(csn, options);
102
91
  return csn;
@@ -144,7 +133,7 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
144
133
 
145
134
  art[_hasLocalizedView] = viewName;
146
135
 
147
- if(acceptLocalizedView && !acceptLocalizedView(viewName, artName))
136
+ if (acceptLocalizedView && !acceptLocalizedView(viewName, artName))
148
137
  return;
149
138
 
150
139
  let view;
@@ -698,6 +687,8 @@ function copyPersistenceAnnotations(target, source) {
698
687
  * @param {CSN.Options} options
699
688
  */
700
689
  function hasExistingLocalizationViews(csn, options) {
690
+ if (!csn || !csn.definitions)
691
+ return false;
701
692
  const firstLocalizedView = Object.keys(csn.definitions).find(isInLocalizedNamespace);
702
693
  if (firstLocalizedView) {
703
694
  const { info } = makeMessageFunction(csn, options);
@@ -201,13 +201,13 @@ module.exports = function (csn, options, referenceFlattener, csnUtils, error, is
201
201
  // Transfer selected type properties from target key element
202
202
  // FIXME: There is currently no other way but to treat the annotation '@odata.Type' as a type property.
203
203
  for (let prop of ['type', 'length', 'scale', 'precision', 'srid', 'default', '@odata.Type']) {
204
- if (fkArtifact[prop] != undefined) {
204
+ if (fkArtifact[prop] !== undefined) {
205
205
  foreignKeyElement[prop] = fkArtifact[prop];
206
206
  }
207
207
  }
208
208
  // If the association is non-fkArtifact resp. key, so should be the foreign key field
209
209
  for (let prop of ['notNull', 'key']) {
210
- if (assoc[prop] != undefined) {
210
+ if (assoc[prop] !== undefined) {
211
211
  foreignKeyElement[prop] = assoc[prop];
212
212
  }
213
213
  }
@@ -9,7 +9,7 @@ const { setProp } = require('../base/model');
9
9
  const { csnRefs } = require('../model/csnRefs');
10
10
 
11
11
  const { copyAnnotations, applyTransformations } = require('../model/csnUtils');
12
- const { cloneCsn, getUtils, isBuiltinType } = require('../model/csnUtils');
12
+ const { cloneCsn, cloneCsnDictionary, getUtils, isBuiltinType } = require('../model/csnUtils');
13
13
 
14
14
  // Return the public functions of this module, with 'model' captured in a closure (for definitions, options etc).
15
15
  // Use 'pathDelimiter' for flattened names (e.g. of struct elements or foreign key elements).
@@ -80,6 +80,14 @@ function getTransformers(model, options, pathDelimiter = '_') {
80
80
  else if(defStrLen5k)
81
81
  element.length = 5000;
82
82
  }
83
+ if (element.type === 'cds.Binary' && element.length === undefined) {
84
+ if(options.defaultBinaryLength) {
85
+ element.length = options.defaultBinaryLength;
86
+ setProp(element, '$default', true);
87
+ }
88
+ else if(defStrLen5k)
89
+ element.length = 5000;
90
+ }
83
91
  /*
84
92
  if (element.type === 'cds.Decimal' && element.precision === undefined && options.precision) {
85
93
  element.precision = options.precision;
@@ -100,7 +108,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
100
108
  // Transfer selected type properties from target key element
101
109
  // FIXME: There is currently no other way but to treat the annotation '@odata.Type' as a type property.
102
110
  for (const prop of ['type', 'length', 'scale', 'precision', 'srid', 'default', '@odata.Type']) {
103
- if (fkArtifact[prop] != undefined) {
111
+ if (fkArtifact[prop] !== undefined) {
104
112
  foreignKeyElement[prop] = fkArtifact[prop];
105
113
  }
106
114
  }
@@ -110,7 +118,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
110
118
 
111
119
  // If the association is non-fkArtifact resp. key, so should be the foreign key field
112
120
  for (const prop of ['notNull', 'key']) {
113
- if (assoc[prop] != undefined) {
121
+ if (assoc[prop] !== undefined) {
114
122
  foreignKeyElement[prop] = assoc[prop];
115
123
  }
116
124
  }
@@ -294,7 +302,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
294
302
  * [ (Entity), (struct1), (struct2), (assoc), (elem) ] should result in
295
303
  * [ (Entity), (struct1_struct2_assoc), (elem) ]
296
304
  *
297
- * @param {string[]} ref
305
+ * @param {string[]} ref
298
306
  * @param {CSN.Path} path CSN path to the ref
299
307
  * @param {object[]} [links] Pre-resolved links for the given ref - if not provided, will be calculated JIT
300
308
  * @param {string} [scope] Pre-resolved scope for the given ref - if not provided, will be calculated JIT
@@ -344,6 +352,8 @@ function getTransformers(model, options, pathDelimiter = '_') {
344
352
  /**
345
353
  * Copy properties of the referenced type, but don't resolve to the final base type.
346
354
  *
355
+ * Do not copy the length if it was just set via the default-value.
356
+ *
347
357
  * @param {any} node Node to copy to
348
358
  * @returns {void}
349
359
  */
@@ -377,7 +387,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
377
387
  * also unravel derived enum types, i.e. take the final base type of the enum's base type.
378
388
  * Similar with associations and compositions (we probably need a _baseType link)
379
389
  *
380
- * @param {CSN.Artifact} node
390
+ * @param {CSN.Artifact} node
381
391
  * @param {WeakMap} [resolved] WeakMap containing already resolved refs
382
392
  * @param {boolean} [keepLocalized=false] Wether to clone .localized from a type def
383
393
  * @returns {void}
@@ -396,7 +406,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
396
406
  delete node.type; // delete the type reference as edm processing does not expect it
397
407
  } else if(finalBaseType.items) {
398
408
  // This changes the order - to be discussed!
399
- node.items = cloneCsn(finalBaseType, options).items; // copy items
409
+ node.items = cloneCsn(finalBaseType.items, options); // copy items
400
410
  delete node.type;
401
411
  } else {
402
412
  node.type=finalBaseType;
@@ -414,16 +424,16 @@ function getTransformers(model, options, pathDelimiter = '_') {
414
424
  return;
415
425
 
416
426
  // cloneCsn only works correctly if we start "from the top"
417
- const clone = cloneCsn({definitions: {'TypeDef': typeDef }}, options);
427
+ const cloneTypeDef = cloneCsn(typeDef, options);
418
428
  // With hdbcds-hdbcds, don't resolve structured types - but propagrate ".items", to turn into LargeString later on.
419
429
  if(typeDef.items) {
420
430
  delete node.type;
421
- Object.assign(node, {items: clone.definitions.TypeDef.items});
431
+ Object.assign(node, {items: cloneTypeDef.items});
422
432
  }
423
433
  if(typeDef.elements && !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds')) {
424
434
  if(!typeDef.items)
425
435
  delete node.type;
426
- Object.assign(node, {elements: clone.definitions.TypeDef.elements});
436
+ Object.assign(node, {elements: cloneTypeDef.elements});
427
437
  }
428
438
 
429
439
 
@@ -431,7 +441,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
431
441
  }
432
442
  // if the declared element is an enum, these values are with priority
433
443
  if (!node.enum && typeDef.enum) {
434
- const clone = cloneCsn({definitions: {'TypeDef': typeDef }}, options).definitions.TypeDef.enum;
444
+ const clone = cloneCsnDictionary(typeDef.enum, options);
435
445
  Object.assign(node, { enum: clone });
436
446
  }
437
447
  if (node.length === undefined && typeDef.length !== undefined)
@@ -855,7 +865,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
855
865
  function checkMultipleAssignments(array, annoName, artifact, artifactName, err = true) {
856
866
  if (array.length > 1) {
857
867
  const loc = ['definitions', artifactName];
858
- if (err == true) {
868
+ if (err === true) {
859
869
  error(null, loc, { anno: annoName }, `Annotation $(ANNO) must be assigned only once`);
860
870
  } else {
861
871
  warning(null, loc, { anno: annoName },`Annotation $(ANNO) must be assigned only once`);
@@ -1074,7 +1084,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
1074
1084
  * Expand structured expression arguments to flat reference paths.
1075
1085
  * Structured elements are real sub element lists and managed associations.
1076
1086
  * All unmanaged association definitions are rewritten if applicable (elements/mixins).
1077
- * Also, HAVING and WHERE clauses are rewritten. We also check for infix filters and
1087
+ * Also, HAVING and WHERE clauses are rewritten. We also check for infix filters and
1078
1088
  * .xpr in columns.
1079
1089
  *
1080
1090
  * @todo Check if can be skipped for abstract entity and or cds.persistence.skip ?
@@ -1084,16 +1094,16 @@ function getTransformers(model, options, pathDelimiter = '_') {
1084
1094
  function expandStructsInExpression(csn, options = {}) {
1085
1095
  applyTransformations(csn, {
1086
1096
  'on': (parent, name, on, path) => {
1087
- parent.on = expand(parent.on, path);
1097
+ parent.on = expand(parent.on, path.concat(name));
1088
1098
  },
1089
1099
  'having': (parent, name, having, path) => {
1090
- parent.having = expand(parent.having, path);
1100
+ parent.having = expand(parent.having, path.concat(name));
1091
1101
  },
1092
1102
  'where': (parent, name, where, path) => {
1093
- parent.where = expand(parent.where, path);
1103
+ parent.where = expand(parent.where, path.concat(name));
1094
1104
  },
1095
1105
  'xpr': (parent, name, xpr, path) => {
1096
- parent.xpr = expand(parent.xpr, path);
1106
+ parent.xpr = expand(parent.xpr, path.concat(name));
1097
1107
  }
1098
1108
  }, undefined, undefined, options);
1099
1109
 
@@ -1111,17 +1121,21 @@ function getTransformers(model, options, pathDelimiter = '_') {
1111
1121
  if(i < expr.length-2)
1112
1122
  {
1113
1123
  const [lhs, op, rhs] = expr.slice(i);
1124
+
1125
+ // we might have to ad-hoc resolve a ref, since handleExists is run before hand and generates new refs.
1126
+ const lhsArt = lhs._art || lhs.ref && !lhs.$scope && inspectRef(location.concat(i)).art;
1127
+ const rhsArt = rhs._art || rhs.ref && !rhs.$scope && inspectRef(location.concat(i+2)).art;
1114
1128
  // lhs & rhs must be expandable types (structures or managed associations)
1115
- if(lhs._art && rhs._art &&
1129
+ if(lhsArt && rhsArt &&
1116
1130
  lhs.ref && rhs.ref &&
1117
- isExpandable(lhs._art) && isExpandable(rhs._art) &&
1131
+ isExpandable(lhsArt) && isExpandable(rhsArt) &&
1118
1132
  ['=', '<', '>', '>=', '<=', '!=', '<>'].includes(op) &&
1119
1133
  !(isDollarSelfOrProjectionOperand(lhs) || isDollarSelfOrProjectionOperand(rhs))) {
1120
1134
 
1121
1135
  // if path is scalar and no assoc or has no type (@Core.Computed) use original expression
1122
1136
  // only do the expansion on (managed) assocs and (items.)elements, array of check in ON cond is done elsewhere
1123
- const lhspaths = /*isScalarOrNoType(lhs._art) ? [ lhs ] : */ flattenPath({ _art: lhs._art, ref: lhs.ref }, false, true );
1124
- const rhspaths = /*isScalarOrNoType(rhs._art) ? [ rhs ] : */ flattenPath({ _art: rhs._art, ref: rhs.ref }, false, true );
1137
+ const lhspaths = /*isScalarOrNoType(lhs._art) ? [ lhs ] : */ flattenPath({ _art: lhsArt, ref: lhs.ref }, false, true );
1138
+ const rhspaths = /*isScalarOrNoType(rhs._art) ? [ rhs ] : */ flattenPath({ _art: rhsArt, ref: rhs.ref }, false, true );
1125
1139
 
1126
1140
  // mapping dict for lhs/rhs for mismatch check
1127
1141
  // strip lhs/rhs prefix from flattened paths to check remaining common trailing path
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const { setProp, forEachGeneric, forEachDefinition, isBetaEnabled } = require('../base/model');
4
- var { makeMessageFunction } = require('../base/messages');
4
+ const { makeMessageFunction } = require('../base/messages');
5
5
  const { recompileX } = require('../compiler/index');
6
- var { linkToOrigin } = require('../compiler/shared');
6
+ const { linkToOrigin, pathName } = require('../compiler/utils');
7
7
  const {compactModel, compactExpr} = require('../json/to-csn');
8
8
  const { deduplicateMessages } = require('../base/messages');
9
- const timetrace = require('../utils/timetrace');
9
+ const { timetrace } = require('../utils/timetrace');
10
10
  // Paths that start with an artifact of protected kind are special
11
11
  // either ignore them in QAT building or in path rewriting
12
12
  const internalArtifactKinds = ['builtin'/*, '$parameters'*/, 'param'];
@@ -179,7 +179,7 @@ function translateAssocsToJoins(model, inputOptions = {})
179
179
  let joinTree = query.from;
180
180
  for(let tan in query.$tableAliases)
181
181
  {
182
- if(!['$projection', '$self'].includes(tan)) // don't drive into $projection/$self tableAlias (yet)
182
+ if(query.$tableAliases[tan].kind !== '$self') // don't drive into $projection/$self tableAlias (yet)
183
183
  {
184
184
  let ta = query.$tableAliases[tan];
185
185
  joinTree = createJoinTree(env, joinTree, ta.$qat, 'left', '$qat', ta.$QA);
@@ -200,7 +200,7 @@ function translateAssocsToJoins(model, inputOptions = {})
200
200
  function createQAForFromClauseSubQuery(query, env)
201
201
  {
202
202
  for (let taName in query.$tableAliases) {
203
- if (!['$self', '$projection'].includes(taName)) {
203
+ if (query.$tableAliases[taName].kind !== '$self') {
204
204
  let ta = query.$tableAliases[taName];
205
205
  if(!ta.$QA) {
206
206
  ta.$QA = createQA(env, ta._origin, taName, undefined);
@@ -241,14 +241,6 @@ function translateAssocsToJoins(model, inputOptions = {})
241
241
  {
242
242
  art.$QA = createQA(env, art.target._artifact, art.name.id );
243
243
  art.$QA.mixin = true;
244
- /* Mark mixin definition to be _ignored:
245
- - If the mixin is used, it is now resolved into a join => definition vaporizes
246
- - If the mixin is published, forHana backend must create a __copy with rewritten
247
- $projection ON conditon and publish it with alias.
248
- - If the mixin is neither be used nor published it shall not be visible to the database
249
- (internal mixin).
250
- */
251
- art.$a2j = { _ignore: true };
252
244
  }
253
245
  });
254
246
  }
@@ -317,13 +309,13 @@ function translateAssocsToJoins(model, inputOptions = {})
317
309
  let [QA, ps] = rightMostQA(tail, head._navigation._parent.$QA || head._navigation.$QA);
318
310
  if(!QA) {
319
311
  error(null, pathNode.$location,
320
- { name: pathNode.path.map(ps=ps.id).join('.') },
312
+ { name: pathName(pathNode.path) },
321
313
  'Please debug me: No QA found for generic path rewriting in $(NAME)')
322
314
  return;
323
315
  }
324
316
  // if the found QA is the mixin QA and if the path length is one,
325
317
  // this indicates the publishing of a mixin assoc, don't rewrite the path
326
- if(QA.mixin && tail.length == 1)
318
+ if(QA.mixin && tail.length === 1)
327
319
  return;
328
320
  let pos = tail.indexOf(ps);
329
321
  // cut off ps if it's a join relevant association with postfix
@@ -678,7 +670,7 @@ function translateAssocsToJoins(model, inputOptions = {})
678
670
  if(fwdAssoc)
679
671
  {
680
672
  //env.assocStack.includes(fwdAssoc) => recursion
681
- if(env.assocStack.length == 2) {
673
+ if(env.assocStack.length === 2) {
682
674
  // reuse (ugly) error message from forHana
683
675
  error(null, env.assocStack[0].location,
684
676
  { name: '$self', id: '$self' },
@@ -710,7 +702,7 @@ function translateAssocsToJoins(model, inputOptions = {})
710
702
  // ON cond of the forward assoc with swapped src/tgt aliases
711
703
  let fwdAssoc = getForwardAssociationExpr(expr);
712
704
  if(fwdAssoc) {
713
- if(env.assocStack.length == 2) {
705
+ if(env.assocStack.length === 2) {
714
706
  // reuse (ugly) error message from forHana
715
707
  error(null, expr.location, 'An association that uses “$self” in its ON-condition can\'t be compared to “$self”');
716
708
  // don't check these paths again
@@ -744,7 +736,7 @@ function translateAssocsToJoins(model, inputOptions = {})
744
736
  let newSrcAlias = tgtAlias;
745
737
  let newTgtAlias = {};
746
738
  // first try to identify table alias for complex views or redirected associations
747
- if(fwdAssoc._redirected && fwdAssoc._redirected.length &&
739
+ if(fwdAssoc._redirected && fwdAssoc._redirected.length &&
748
740
  // redirected target must have a $QA
749
741
  fwdAssoc._redirected[fwdAssoc._redirected.length-1].$QA &&
750
742
  // $QA's artifact must either be same srcAlias artifact
@@ -920,7 +912,7 @@ function translateAssocsToJoins(model, inputOptions = {})
920
912
  combined list of elements made available by the from clause.
921
913
  */
922
914
  let _navigation = undefined; // don't modify original path
923
- if(env.assocStack.length == 2) {
915
+ if(env.assocStack.length === 2) {
924
916
  // a mixin assoc cannot have a structure prefix, it's sufficient to check head
925
917
  if(head.id === env.assocStack.id()) {
926
918
  // source side from view point of view (target side from forward point of view)
@@ -982,7 +974,7 @@ function translateAssocsToJoins(model, inputOptions = {})
982
974
 
983
975
  // Return the original association if expr is a backlink term, undefined otherwise
984
976
  function getForwardAssociationExpr(expr) {
985
- if(expr.op && expr.op.val === '=' && expr.args.length == 2) {
977
+ if(expr.op && expr.op.val === '=' && expr.args.length === 2) {
986
978
  return getForwardAssociation(expr.args[0].path, expr.args[1].path);
987
979
  }
988
980
  return undefined;
@@ -991,10 +983,10 @@ function translateAssocsToJoins(model, inputOptions = {})
991
983
  function getForwardAssociation(lhs, rhs) {
992
984
  // [alpha.]BACKLINK.[beta.]FORWARD
993
985
  if(lhs && rhs) {
994
- if(rhs.length == 1 && rhs[0].id === '$self' &&
986
+ if(rhs.length === 1 && rhs[0].id === '$self' &&
995
987
  lhs.length > 1 && hasPrefix(lhs))
996
988
  return lhs[lhs.length-1]._artifact;
997
- if(lhs.length == 1 && lhs[0].id === '$self' &&
989
+ if(lhs.length === 1 && lhs[0].id === '$self' &&
998
990
  rhs.length > 1 && hasPrefix(rhs))
999
991
  return rhs[rhs.length-1]._artifact;
1000
992
  }
@@ -1403,7 +1395,7 @@ function translateAssocsToJoins(model, inputOptions = {})
1403
1395
 
1404
1396
  let [head, ...tail] = path;
1405
1397
 
1406
- if(['$projection', '$self'].includes(head.id) && tail.length) {
1398
+ if(['$projection', '$self'].includes(head.id) && tail.length && head._navigation.kind === '$self') {
1407
1399
  // make sure not to truncate tail
1408
1400
  if(tail.length > 1)
1409
1401
  [head, ...tail] = tail;