@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.
- package/CHANGELOG.md +35 -0
- package/bin/cdsc.js +11 -4
- package/lib/api/options.js +1 -1
- package/lib/base/message-registry.js +36 -7
- package/lib/base/messages.js +11 -4
- package/lib/base/model.js +0 -1
- package/lib/checks/assocOutsideService.js +17 -30
- package/lib/checks/checkForTypes.js +0 -18
- package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
- package/lib/checks/onConditions.js +2 -2
- package/lib/checks/queryNoDbArtifacts.js +16 -15
- package/lib/checks/types.js +1 -1
- package/lib/checks/utils.js +30 -6
- package/lib/checks/validator.js +4 -5
- package/lib/compiler/checks.js +47 -18
- package/lib/compiler/index.js +88 -6
- package/lib/compiler/resolve.js +7 -7
- package/lib/compiler/tweak-assocs.js +47 -25
- package/lib/gen/BaseParser.js +1 -1
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +381 -378
- package/lib/gen/Dictionary.json +0 -2
- package/lib/model/csnRefs.js +9 -4
- package/lib/model/csnUtils.js +67 -2
- package/lib/optionProcessor.js +2 -3
- package/lib/parsers/AstBuildingParser.js +5 -6
- package/lib/render/toCdl.js +10 -4
- package/lib/render/utils/common.js +4 -2
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/associations.js +37 -1
- package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
- package/lib/transform/db/assocsToQueries/utils.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/expansion.js +37 -36
- package/lib/transform/draft/db.js +20 -20
- package/lib/transform/draft/odata.js +38 -40
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/effective/flattening.js +40 -47
- package/lib/transform/effective/main.js +6 -4
- package/lib/transform/forOdata.js +135 -115
- package/lib/transform/forRelationalDB.js +151 -142
- package/lib/transform/localized.js +116 -109
- package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
- package/lib/transform/odata/createForeignKeys.js +73 -70
- package/lib/transform/odata/flattening.js +216 -200
- package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
- package/lib/transform/odata/toFinalBaseType.js +40 -39
- package/lib/transform/odata/typesExposure.js +151 -133
- package/lib/transform/odata/utils.js +7 -6
- package/lib/transform/parseExpr.js +165 -162
- package/lib/transform/transformUtils.js +184 -551
- package/lib/transform/translateAssocsToJoins.js +510 -571
- package/lib/transform/tupleExpansion.js +495 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/package.json +1 -1
- package/lib/base/cleanSymbols.js +0 -17
- 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
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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)
|
|
284
|
+
if (sourceElement.key)
|
|
285
|
+
targetElement.notNull = true;
|
|
286
286
|
|
|
287
|
-
draftsArtifact.elements[
|
|
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 {
|
|
3
|
+
const {
|
|
4
|
+
forEachDefinition, forEachMemberRecursively,
|
|
4
5
|
getServiceNames, applyAnnotationsFromExtensions,
|
|
5
|
-
transformAnnotationExpression
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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(
|
|
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(
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
64
|
+
transformerUtils.expandStructsInExpression({ drillRef: true });
|
|
63
65
|
|
|
64
66
|
messageFunctions.throwWithAnyError();
|
|
65
67
|
|