@sap/cds-compiler 6.2.2 → 6.3.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 (57) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/bin/cdsc.js +11 -4
  3. package/lib/api/options.js +1 -1
  4. package/lib/base/message-registry.js +36 -7
  5. package/lib/base/messages.js +11 -4
  6. package/lib/base/model.js +0 -1
  7. package/lib/checks/assocOutsideService.js +17 -30
  8. package/lib/checks/checkForTypes.js +0 -18
  9. package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
  10. package/lib/checks/onConditions.js +2 -2
  11. package/lib/checks/queryNoDbArtifacts.js +16 -15
  12. package/lib/checks/types.js +1 -1
  13. package/lib/checks/utils.js +30 -6
  14. package/lib/checks/validator.js +4 -5
  15. package/lib/compiler/checks.js +47 -18
  16. package/lib/compiler/index.js +88 -6
  17. package/lib/compiler/resolve.js +7 -7
  18. package/lib/compiler/tweak-assocs.js +47 -25
  19. package/lib/gen/BaseParser.js +1 -1
  20. package/lib/gen/CdlGrammar.checksum +1 -1
  21. package/lib/gen/CdlParser.js +381 -378
  22. package/lib/gen/Dictionary.json +0 -2
  23. package/lib/model/csnRefs.js +9 -4
  24. package/lib/model/csnUtils.js +67 -2
  25. package/lib/optionProcessor.js +2 -3
  26. package/lib/parsers/AstBuildingParser.js +5 -6
  27. package/lib/render/toCdl.js +10 -4
  28. package/lib/render/utils/common.js +4 -2
  29. package/lib/transform/db/assertUnique.js +2 -1
  30. package/lib/transform/db/associations.js +37 -1
  31. package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
  32. package/lib/transform/db/assocsToQueries/utils.js +1 -1
  33. package/lib/transform/db/cdsPersistence.js +1 -1
  34. package/lib/transform/db/expansion.js +37 -36
  35. package/lib/transform/draft/db.js +20 -20
  36. package/lib/transform/draft/odata.js +38 -40
  37. package/lib/transform/effective/associations.js +1 -1
  38. package/lib/transform/effective/flattening.js +40 -47
  39. package/lib/transform/effective/main.js +6 -4
  40. package/lib/transform/forOdata.js +135 -115
  41. package/lib/transform/forRelationalDB.js +151 -142
  42. package/lib/transform/localized.js +116 -109
  43. package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
  44. package/lib/transform/odata/createForeignKeys.js +73 -70
  45. package/lib/transform/odata/flattening.js +216 -200
  46. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
  47. package/lib/transform/odata/toFinalBaseType.js +40 -39
  48. package/lib/transform/odata/typesExposure.js +151 -133
  49. package/lib/transform/odata/utils.js +7 -6
  50. package/lib/transform/parseExpr.js +165 -162
  51. package/lib/transform/transformUtils.js +184 -551
  52. package/lib/transform/translateAssocsToJoins.js +510 -571
  53. package/lib/transform/tupleExpansion.js +495 -0
  54. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  55. package/package.json +1 -1
  56. package/lib/base/cleanSymbols.js +0 -17
  57. package/lib/checks/nonexpandableStructured.js +0 -39
@@ -4,7 +4,7 @@ const {
4
4
  getServiceNames, forEachDefinition,
5
5
  getResultingName, forEachMemberRecursively, applyAnnotationsFromExtensions,
6
6
  } = require('../../model/csnUtils');
7
- const { setProp, isBetaEnabled } = require('../../base/model');
7
+ const { setProp } = require('../../base/model');
8
8
  const { getTransformers } = require('../transformUtils');
9
9
  const { ModelError } = require('../../base/error');
10
10
  const { forEach } = require('../../utils/objectUtils');
@@ -56,10 +56,10 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
56
56
 
57
57
  // Redirect associations/compositions between draft shadow nodes
58
58
  for (const name in draftNodes) {
59
- const shadowNode = csn.definitions[`${name}${draftSuffix}`];
59
+ const shadowNode = csn.definitions[`${ name }${ draftSuffix }`];
60
60
  // Might not exist because of previous errors
61
61
  if (shadowNode)
62
- redirectDraftTargets(csn.definitions[`${name}${draftSuffix}`], draftNodes);
62
+ redirectDraftTargets(csn.definitions[`${ name }${ draftSuffix }`], draftNodes);
63
63
  }
64
64
  }
65
65
  }
@@ -84,7 +84,7 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
84
84
  const draftNodeName = elem.target;
85
85
  // Sanity check
86
86
  if (!draftNode)
87
- throw new ModelError(`Expecting target to be resolved: ${JSON.stringify(elem, null, 2)}`);
87
+ throw new ModelError(`Expecting target to be resolved: ${ JSON.stringify(elem, null, 2) }`);
88
88
 
89
89
  // Ignore composition if not part of a service
90
90
  if (!isPartOfService(draftNodeName)) {
@@ -115,11 +115,11 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
115
115
  function generateDraftForHana( artifact, artifactName, draftRootName ) {
116
116
  // Sanity check
117
117
  if (!isPartOfService(artifactName))
118
- throw new ModelError(`Expecting artifact to be part of a service: ${JSON.stringify(artifact)}`);
118
+ throw new ModelError(`Expecting artifact to be part of a service: ${ JSON.stringify(artifact) }`);
119
119
 
120
120
 
121
121
  // The name of the draft shadow entity we should generate
122
- const draftsArtifactName = `${artifactName}${draftSuffix}`;
122
+ const draftsArtifactName = `${ artifactName }${ draftSuffix }`;
123
123
 
124
124
  generatedArtifacts[draftsArtifactName] = true;
125
125
 
@@ -132,7 +132,7 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
132
132
  // Ignore boolean return value. We know that we're inside a service or else we wouldn't have reached this code.
133
133
  const matchingService = getMatchingService(artifactName) || '';
134
134
  // Generate the DraftAdministrativeData projection into the service, unless there is already one
135
- const draftAdminDataProjectionName = `${matchingService}.DraftAdministrativeData`;
135
+ const draftAdminDataProjectionName = `${ matchingService }.DraftAdministrativeData`;
136
136
  let draftAdminDataProjection = csn.definitions[draftAdminDataProjectionName];
137
137
  if (!draftAdminDataProjection) {
138
138
  generatedArtifacts[draftAdminDataProjectionName] = true;
@@ -232,10 +232,9 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
232
232
  draftAdministrativeData.DraftAdministrativeData.notNull = true;
233
233
  addElement(draftAdministrativeData, draftsArtifact, artifactName);
234
234
 
235
- if (isBetaEnabled(options, 'draftMessages') || options.draftMessages) {
236
- const draftMessages = { DraftMessages: { '@Core.Computed': true, virtual: true, items: { type: 'DRAFT.DraftAdministrativeData_DraftMessage' } } };
237
- addElement(draftMessages, draftsArtifact, artifactName);
238
- }
235
+ const draftMessages = { DraftMessages: { '@Core.Computed': true, virtual: true, items: { type: 'DRAFT.DraftAdministrativeData_DraftMessage' } } };
236
+ addElement(draftMessages, draftsArtifact, artifactName);
237
+
239
238
  // Note that we may need to do the HANA transformation steps for managed associations
240
239
  // (foreign key field generation, generatedFieldName, creating ON-condition) by hand,
241
240
  // because the corresponding transformation steps have already been done on all artifacts
@@ -278,18 +277,19 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
278
277
  const sourceElement = source.elements[draftUUIDKey.ref[0]];
279
278
  const targetElement = {};
280
279
  forEach(sourceElement, (key, value) => {
281
- if(!key.startsWith('@') && key !== 'key')
280
+ if (!key.startsWith('@') && key !== 'key')
282
281
  targetElement[key] = value;
283
- })
282
+ });
284
283
 
285
- if(sourceElement.key) targetElement.notNull = true;
284
+ if (sourceElement.key)
285
+ targetElement.notNull = true;
286
286
 
287
- draftsArtifact.elements['DraftAdministrativeData' + (options.sqlMapping === 'hdbcds' ? '.' : '_') + draftUUIDKey.ref[0]] = targetElement;
287
+ draftsArtifact.elements[`DraftAdministrativeData${ options.sqlMapping === 'hdbcds' ? '.' : '_' }${ draftUUIDKey.ref[0] }`] = targetElement;
288
288
 
289
289
  draftAdministrativeData.DraftAdministrativeData.on = createAssociationPathComparison('DraftAdministrativeData',
290
290
  getNameForRef(draftUUIDKey),
291
291
  '=',
292
- `DraftAdministrativeData${pathDelimiter}DraftUUID`);
292
+ `DraftAdministrativeData${ pathDelimiter }DraftUUID`);
293
293
  // The notNull has been transferred to the foreign key field and must be removed on the association
294
294
  delete draftAdministrativeData.DraftAdministrativeData.notNull;
295
295
 
@@ -337,9 +337,9 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
337
337
  function getDraftShadowEntityFor( draftNode, draftNodeName ) {
338
338
  // Sanity check
339
339
  if (!draftNodes[draftNodeName])
340
- throw new ModelError(`Not a draft node: ${draftNodeName}`);
340
+ throw new ModelError(`Not a draft node: ${ draftNodeName }`);
341
341
 
342
- return { shadowTarget: csn.definitions[`${draftNodeName}${draftSuffix}`], shadowTargetName: `${draftNodeName}${draftSuffix}` };
342
+ return { shadowTarget: csn.definitions[`${ draftNodeName }${ draftSuffix }`], shadowTargetName: `${ draftNodeName }${ draftSuffix }` };
343
343
  }
344
344
  }
345
345
 
@@ -351,7 +351,7 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
351
351
  */
352
352
  function isPartOfService( artifactName ) {
353
353
  for (const serviceName of allServices) {
354
- if (artifactName.startsWith(`${serviceName}.`))
354
+ if (artifactName.startsWith(`${ serviceName }.`))
355
355
  return true;
356
356
  }
357
357
 
@@ -369,7 +369,7 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
369
369
  /** @type {false|string} */
370
370
  let match = false;
371
371
  for (const serviceName of allServices) {
372
- if (artifactName.startsWith(`${serviceName}.`) && (!match || serviceName.length < match.length))
372
+ if (artifactName.startsWith(`${ serviceName }.`) && (!match || serviceName.length < match.length))
373
373
  match = serviceName;
374
374
  }
375
375
  return match;
@@ -1,13 +1,14 @@
1
1
  'use strict';
2
2
 
3
- const { forEachDefinition, forEachMemberRecursively,
3
+ const {
4
+ forEachDefinition, forEachMemberRecursively,
4
5
  getServiceNames, applyAnnotationsFromExtensions,
5
- transformAnnotationExpression } = require('../../model/csnUtils');
6
+ transformAnnotationExpression,
7
+ } = require('../../model/csnUtils');
6
8
  const { forEach } = require('../../utils/objectUtils');
7
9
  const { isArtifactInSomeService, getServiceOfArtifact } = require('../odata/utils');
8
10
  const { getTransformers } = require('../transformUtils');
9
11
  const { makeMessageFunction } = require('../../base/messages');
10
- const { isBetaEnabled } = require('../../base/model');
11
12
 
12
13
  /**
13
14
  * - Generate artificial draft fields if requested
@@ -59,7 +60,7 @@ function generateDrafts( csn, options, services, messageFunctions ) {
59
60
  const filterDict = Object.create(null);
60
61
 
61
62
  // validate the 'DRAFT.DraftAdministrativeData_DraftMessage' type if already present in the model
62
- if (isBetaEnabled(options, 'draftMessages') || options.draftMessages) {
63
+ if (options.draftMessages) {
63
64
  const draftAdminDataMessagesType = csn.definitions['DRAFT.DraftAdministrativeData_DraftMessage'];
64
65
  if (draftAdminDataMessagesType && !isValidDraftAdminDataMessagesType(draftAdminDataMessagesType)) {
65
66
  error(null, [ 'definitions', 'DRAFT.DraftAdministrativeData_DraftMessage' ], { name: 'DRAFT.DraftAdministrativeData_DraftMessage' },
@@ -98,7 +99,7 @@ function generateDrafts( csn, options, services, messageFunctions ) {
98
99
  artifact.actions && artifact.actions.draftPrepare)
99
100
  return;
100
101
 
101
- if(!visitedArtifacts[artifactName])
102
+ if (!visitedArtifacts[artifactName])
102
103
  visitedArtifacts[artifactName] = artifact;
103
104
 
104
105
  const draftPrepare = createAction('draftPrepare', artifactName, 'SideEffectsQualifier', 'cds.String');
@@ -118,7 +119,7 @@ function generateDrafts( csn, options, services, messageFunctions ) {
118
119
 
119
120
  // Generate the DraftAdministrativeData projection into the service, unless there is already one
120
121
  // @ts-ignore
121
- const draftAdminDataProjectionName = `${getServiceOfArtifact(artifactName, services)}.DraftAdministrativeData`;
122
+ const draftAdminDataProjectionName = `${ getServiceOfArtifact(artifactName, services) }.DraftAdministrativeData`;
122
123
  let draftAdminDataProjection = csn.definitions[draftAdminDataProjectionName];
123
124
  if (!draftAdminDataProjection) {
124
125
  // @ts-ignore
@@ -180,19 +181,15 @@ function generateDrafts( csn, options, services, messageFunctions ) {
180
181
  // ... on SiblingEntity.IsActiveEntity != IsActiveEntity ...
181
182
  siblingEntity.SiblingEntity.on = createAssociationPathComparison('SiblingEntity', 'IsActiveEntity', '!=', 'IsActiveEntity');
182
183
 
183
- if (isBetaEnabled(options, 'draftMessages') || options.draftMessages) {
184
+ if (options.draftMessages) {
184
185
  const draftMessages = { DraftMessages: { '@Core.Computed': true, virtual: true, items: { type: 'DRAFT.DraftAdministrativeData_DraftMessage' } } };
185
186
  addElement(draftMessages, artifact, artifactName);
186
187
 
187
188
  if (!artifact['@Common.SideEffects#alwaysFetchMessages'] && artifact['@Common.SideEffects#alwaysFetchMessages'] !== null) {
188
- setAnnotation(artifact, '@Common.SideEffects#alwaysFetchMessages.SourceEntities', ['']);
189
- setAnnotation(artifact, '@Common.SideEffects#alwaysFetchMessages.TargetProperties', ['DraftMessages'] );
189
+ setAnnotation(artifact, '@Common.SideEffects#alwaysFetchMessages.SourceEntities', [ '' ]);
190
+ setAnnotation(artifact, '@Common.SideEffects#alwaysFetchMessages.TargetProperties', [ 'DraftMessages' ] );
190
191
  }
191
- setAnnotation(artifact, '@Common.Messages', { '=': 'DraftMessages', ref: ['DraftMessages'] });
192
- setAnnotationAddressViaNavigationPath(artifactName, services);
193
- }
194
-
195
- if (options.addAnnotationAddressViaNavigationPath) {
192
+ setAnnotation(artifact, '@Common.Messages', { '=': 'DraftMessages', ref: [ 'DraftMessages' ] });
196
193
  setAnnotationAddressViaNavigationPath(artifactName, services);
197
194
  }
198
195
 
@@ -249,50 +246,51 @@ function generateDrafts( csn, options, services, messageFunctions ) {
249
246
  }
250
247
  }
251
248
 
252
- /*
253
- * After draft decoration, all visited artifacts are supposed to have the draft state elements
254
- * Is/HasActiveEntity, HasDraftEntity. Now, $draft.<postfix> (with postfix defined as magic variable
255
- * in the core compiler builtins) needs to be translated into $self.<postfix>.
256
- *
257
- * It has to be processed after the late 'applyAnnotationsFromExtensions' which could also merge in
258
- * some $draft path expressions.
249
+ /*
250
+ * After draft decoration, all visited artifacts are supposed to have the draft state elements
251
+ * Is/HasActiveEntity, HasDraftEntity. Now, $draft.<postfix> (with postfix defined as magic variable
252
+ * in the core compiler builtins) needs to be translated into $self.<postfix>.
253
+ *
254
+ * It has to be processed after the late 'applyAnnotationsFromExtensions' which could also merge in
255
+ * some $draft path expressions.
259
256
  */
260
257
  function rewriteDollarDraft() {
261
-
262
258
  function $draft2$self(member) {
263
- Object.keys(member).forEach(pn => {
264
- if(pn[0] === '@') {
259
+ Object.keys(member).forEach((pn) => {
260
+ if (pn[0] === '@') {
265
261
  transformAnnotationExpression(member, pn, {
266
- ref: (_parent, _prop, xpr, _path, _p, _ppn, ctx) => {
267
- if(xpr[0] === '$draft') {
268
- xpr[0] = '$self';
269
- if(ctx?.annoExpr?.['='])
270
- ctx.annoExpr['='] = true;
271
- }
262
+ ref: (_parent, _prop, xpr, _path, _p, _ppn, ctx) => {
263
+ if (xpr[0] === '$draft') {
264
+ xpr[0] = '$self';
265
+ if (ctx?.annoExpr?.['='])
266
+ ctx.annoExpr['='] = true;
272
267
  }
273
268
  },
274
- );
269
+ });
275
270
  }
276
271
  });
277
272
  }
278
273
 
279
274
  // entity parameters are not substituted as the EDM param entity is not draft enabled
280
- Object.entries(visitedArtifacts).forEach(([artName, art]) => {
275
+ Object.entries(visitedArtifacts).forEach(([ artName, art ]) => {
281
276
  $draft2$self(art);
282
- forEachMemberRecursively(art, $draft2$self,
277
+ forEachMemberRecursively(
278
+ art, $draft2$self,
283
279
  [ 'definitions', artName ],
284
280
  true, { elementsOnly: true }
285
281
  );
286
- if(art.actions) {
287
- Object.entries(art.actions).forEach(([actionName, action]) => {
282
+ if (art.actions) {
283
+ Object.entries(art.actions).forEach(([ actionName, action ]) => {
288
284
  $draft2$self(action);
289
- forEachMemberRecursively(action, $draft2$self,
290
- [ 'definitions', artName, 'actions', actionName ]);
291
- if(action.returns)
285
+ forEachMemberRecursively(
286
+ action, $draft2$self,
287
+ [ 'definitions', artName, 'actions', actionName ]
288
+ );
289
+ if (action.returns)
292
290
  $draft2$self(action.returns);
293
- })
291
+ });
294
292
  }
295
- })
293
+ });
296
294
  }
297
295
 
298
296
  // Set the @Common.AddressViaNavigationPath annotation to the service of
@@ -43,7 +43,7 @@ function turnAssociationsIntoUnmanaged( csn, options, csnUtils, messageFunctions
43
43
  orderBy: expandManagedToFksInArray(true),
44
44
  }, [], { allowArtifact: artifact => artifact.query !== undefined || artifact.projection !== undefined });
45
45
 
46
- forEachDefinition(csn, associations.getFKAccessFinalizer(csn, csnUtils, '_', true));
46
+ forEachDefinition(csn, associations.getFKAccessFinalizer(csn, options, csnUtils, '_', true));
47
47
  applyTransformations(csn, {
48
48
  elements: (_parent, prop, elements, path) => {
49
49
  forEachMember(_parent, (element, elementName, _prop, elPath) => {
@@ -55,54 +55,47 @@ function flattenRefs(csn, options, csnUtils, messageFunctions) {
55
55
  const refFlattener = getStructStepsFlattener(csn, options, messageFunctions, resolved, '_', adaptRefs);
56
56
 
57
57
  forEachDefinition(csn, (def, defName) => {
58
- if (def.kind === 'entity') {
59
- applyTransformationsOnNonDictionary(csn.definitions, defName, refFlattener, { processAnnotations: true, skipDict: { actions: 1 } }, [ 'definitions' ]);
60
-
61
- adaptRefs.forEach(fn => fn());
62
- adaptRefs.length = 0;
63
-
64
- // explicit binding parameter of bound action
65
- if (def.actions) {
66
- const special$self = !csn?.definitions?.$self && '$self';
67
- Object.entries(def.actions).forEach(([ an, a ]) => {
68
- if (a.params) {
69
- const params = Object.entries(a.params);
70
- const firstParam = params[0][1];
71
- const type = firstParam?.items?.type || firstParam?.type;
72
- if (type === special$self) {
73
- const bindingParamName = params[0][0];
74
- const markBindingParam = {
75
- ref: (parent, prop, xpr) => {
76
- if ((xpr[0].id || xpr[0]) === bindingParamName)
77
- setProp(parent, '$bparam', true);
78
- },
79
- };
80
-
81
- Object.keys(a)
82
- .filter(pn => pn.startsWith('@') && a[pn])
83
- .forEach((pn) => {
84
- transformAnnotationExpression(a, pn, [ markBindingParam, refFlattener ], [ 'definitions', defName, 'actions', an ]);
85
- adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
86
- adaptRefs.length = 0;
87
- });
88
-
89
-
90
- forEachMemberRecursively(a, (member, memberName, prop, path) => {
91
- Object.keys(member).filter(pn => pn.startsWith('@') && member[pn]).forEach((pn) => {
92
- transformAnnotationExpression(member, pn, [ markBindingParam, refFlattener ], path);
93
- adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
94
- adaptRefs.length = 0;
95
- });
96
- }, [ 'definitions', defName, 'actions', an ]);
97
- }
58
+ applyTransformationsOnNonDictionary(csn.definitions, defName, refFlattener, { processAnnotations: true, skipDict: { actions: 1 } }, [ 'definitions' ]);
59
+
60
+ adaptRefs.forEach(fn => fn());
61
+ adaptRefs.length = 0;
62
+
63
+ // explicit binding parameter of bound action
64
+ if (def.actions) {
65
+ const special$self = !csn?.definitions?.$self && '$self';
66
+ Object.entries(def.actions).forEach(([ an, a ]) => {
67
+ if (a.params) {
68
+ const params = Object.entries(a.params);
69
+ const firstParam = params[0][1];
70
+ const type = firstParam?.items?.type || firstParam?.type;
71
+ if (type === special$self) {
72
+ const bindingParamName = params[0][0];
73
+ const markBindingParam = {
74
+ ref: (parent, prop, xpr) => {
75
+ if ((xpr[0].id || xpr[0]) === bindingParamName)
76
+ setProp(parent, '$bparam', true);
77
+ },
78
+ };
79
+
80
+ Object.keys(a)
81
+ .filter(pn => pn.startsWith('@') && a[pn])
82
+ .forEach((pn) => {
83
+ transformAnnotationExpression(a, pn, [ markBindingParam, refFlattener ], [ 'definitions', defName, 'actions', an ]);
84
+ adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
85
+ adaptRefs.length = 0;
86
+ });
87
+
88
+
89
+ forEachMemberRecursively(a, (member, memberName, prop, path) => {
90
+ Object.keys(member).filter(pn => pn.startsWith('@') && member[pn]).forEach((pn) => {
91
+ transformAnnotationExpression(member, pn, [ markBindingParam, refFlattener ], path);
92
+ adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
93
+ adaptRefs.length = 0;
94
+ });
95
+ }, [ 'definitions', defName, 'actions', an ]);
98
96
  }
99
- });
100
- }
101
- }
102
- else {
103
- applyTransformationsOnNonDictionary(csn.definitions, defName, refFlattener, { processAnnotations: false }, [ 'definitions' ]);
104
- adaptRefs.forEach(fn => fn());
105
- adaptRefs.length = 0;
97
+ }
98
+ });
106
99
  }
107
100
  });
108
101
 
@@ -39,10 +39,12 @@ function effectiveCsn( model, options, messageFunctions ) {
39
39
  messageFunctions.setModel(csn);
40
40
 
41
41
  const transformerUtils = transformUtils.getTransformers(csn, options, messageFunctions, '_');
42
- const { expandStructsInExpression } = transformerUtils;
43
42
  const redoProjections = queries.projectionToSELECTAndAddColumns(csn);
44
43
 
45
- let csnUtils = getUtils(csn, 'init-all');
44
+ // re-use from transformers; otherwise we have two caches and tuple expansion
45
+ // would use a different one than handleExists, leading to unnecessary re-initialization
46
+ let { csnUtils } = transformerUtils;
47
+ csnUtils.initAllDefinitions();
46
48
 
47
49
  // Run validations on CSN - each validator function has access to the message functions and the inspect ref via this
48
50
  const cleanup = validate.forRelationalDB(csn, {
@@ -53,13 +55,13 @@ function effectiveCsn( model, options, messageFunctions ) {
53
55
  rewriteCalculatedElementsInViews(csn, options, csnUtils, '_', messageFunctions);
54
56
 
55
57
  // Needs to happen before tuple expansion, so the newly generated WHERE-conditions have it applied
56
- handleExists(csn, options, messageFunctions.error, csnUtils.inspectRef, csnUtils.initDefinition, csnUtils.dropDefinitionCache);
58
+ handleExists(csn, options, messageFunctions, csnUtils);
57
59
 
58
60
  // Check if structured elements and managed associations are compared in an expression
59
61
  // and expand these structured elements. This tuple expansion allows all other
60
62
  // subsequent procession steps to see plain paths in expressions.
61
63
  // If errors are detected, throwWithAnyError() will return from further processing
62
- expandStructsInExpression(csn, { drillRef: true });
64
+ transformerUtils.expandStructsInExpression({ drillRef: true });
63
65
 
64
66
  messageFunctions.throwWithAnyError();
65
67