@sap/cds-compiler 2.13.8 → 2.15.6
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 +128 -4
- package/bin/cdsc.js +112 -37
- package/lib/api/main.js +63 -22
- package/lib/api/options.js +2 -3
- package/lib/api/validate.js +6 -6
- package/lib/base/message-registry.js +100 -17
- package/lib/base/messages.js +85 -64
- package/lib/base/optionProcessorHelper.js +19 -0
- package/lib/checks/annotationsOData.js +11 -32
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/validator.js +2 -4
- package/lib/compiler/assert-consistency.js +1 -0
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +11 -0
- package/lib/compiler/checks.js +22 -70
- package/lib/compiler/define.js +59 -11
- package/lib/compiler/extend.js +20 -3
- package/lib/compiler/finalize-parse-cdl.js +26 -20
- package/lib/compiler/index.js +75 -26
- package/lib/compiler/populate.js +36 -17
- package/lib/compiler/propagator.js +4 -1
- package/lib/compiler/resolve.js +104 -16
- package/lib/compiler/shared.js +61 -27
- package/lib/compiler/tweak-assocs.js +7 -1
- package/lib/edm/annotations/genericTranslation.js +93 -21
- package/lib/edm/csn2edm.js +216 -98
- package/lib/edm/edm.js +305 -226
- package/lib/edm/edmPreprocessor.js +499 -423
- package/lib/edm/edmUtils.js +22 -22
- package/lib/gen/Dictionary.json +98 -22
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageParser.js +4636 -4368
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +3 -2
- package/lib/json/to-csn.js +0 -2
- package/lib/language/docCommentParser.js +2 -2
- package/lib/language/genericAntlrParser.js +47 -2
- package/lib/language/language.g4 +59 -27
- package/lib/main.d.ts +19 -1
- package/lib/main.js +6 -0
- package/lib/model/csnRefs.js +33 -6
- package/lib/model/csnUtils.js +193 -75
- package/lib/model/enrichCsn.js +1 -0
- package/lib/model/revealInternalProperties.js +2 -2
- package/lib/modelCompare/compare.js +6 -6
- package/lib/optionProcessor.js +62 -26
- package/lib/render/toCdl.js +844 -679
- package/lib/render/toHdbcds.js +189 -243
- package/lib/render/toSql.js +180 -198
- package/lib/render/utils/common.js +131 -15
- package/lib/transform/db/.eslintrc.json +1 -1
- package/lib/transform/db/associations.js +2 -2
- package/lib/transform/db/constraints.js +3 -1
- package/lib/transform/db/expansion.js +15 -10
- package/lib/transform/db/flattening.js +94 -64
- package/lib/transform/db/transformExists.js +7 -7
- package/lib/transform/db/views.js +6 -3
- package/lib/transform/forHanaNew.js +43 -26
- package/lib/transform/forOdataNew.js +43 -42
- package/lib/transform/localized.js +12 -7
- package/lib/transform/odata/toFinalBaseType.js +8 -6
- package/lib/transform/odata/typesExposure.js +145 -197
- package/lib/transform/transformUtilsNew.js +9 -12
- package/lib/transform/translateAssocsToJoins.js +5 -1
- package/lib/transform/universalCsn/coreComputed.js +5 -3
- package/lib/transform/universalCsn/universalCsnEnricher.js +27 -5
- package/lib/utils/moduleResolve.js +13 -6
- package/package.json +1 -1
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -296
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { setProp, isBetaEnabled } = require('../base/model');
|
|
4
|
-
const { getUtils,
|
|
4
|
+
const { getUtils, cloneCsnNonDict,
|
|
5
5
|
forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
|
|
6
6
|
getArtifactDatabaseNameOf, getElementDatabaseNameOf, isBuiltinType, applyTransformations,
|
|
7
7
|
isAspect, walkCsnPath,
|
|
@@ -16,7 +16,7 @@ const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../che
|
|
|
16
16
|
const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
|
|
17
17
|
const { timetrace } = require('../utils/timetrace');
|
|
18
18
|
const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
|
|
19
|
-
const { createDict } = require('../utils/objectUtils');
|
|
19
|
+
const { createDict, forEach } = require('../utils/objectUtils');
|
|
20
20
|
const handleExists = require('./db/transformExists');
|
|
21
21
|
const replaceAssociationsInGroupByOrderBy = require('./db/groupByOrderBy');
|
|
22
22
|
const _forEachDefinition = require('../model/csnUtils').forEachDefinition;
|
|
@@ -106,7 +106,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
106
106
|
// copy the model as we don't want to change the input model
|
|
107
107
|
timetrace.start('HANA transformation');
|
|
108
108
|
/** @type {CSN.Model} */
|
|
109
|
-
let csn =
|
|
109
|
+
let csn = cloneCsnNonDict(inputModel, options);
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
|
|
@@ -116,14 +116,14 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
116
116
|
|
|
117
117
|
let message, error, warning, info; // message functions
|
|
118
118
|
/** @type {() => void} */
|
|
119
|
-
let
|
|
119
|
+
let throwWithAnyError;
|
|
120
120
|
let artifactRef, inspectRef, effectiveType, get$combined,
|
|
121
121
|
getFinalBaseType, // csnUtils (csnRefs)
|
|
122
122
|
addDefaultTypeFacets, expandStructsInExpression; // transformUtils
|
|
123
123
|
|
|
124
124
|
bindCsnReference();
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
throwWithAnyError(); // reclassify and throw in case of non-configurable errors
|
|
127
127
|
|
|
128
128
|
if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn')) {
|
|
129
129
|
enrichUniversalCsn(csn, options);
|
|
@@ -146,13 +146,13 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
146
146
|
// Check if structured elements and managed associations are compared in an expression
|
|
147
147
|
// and expand these structured elements. This tuple expansion allows all other
|
|
148
148
|
// subsequent procession steps (especially a2j) to see plain paths in expressions.
|
|
149
|
-
// If errors are detected,
|
|
149
|
+
// If errors are detected, throwWithAnyError() will return from further processing
|
|
150
150
|
|
|
151
151
|
// If this function is ever undefined, we have a bug in our logic.
|
|
152
152
|
// @ts-ignore
|
|
153
153
|
expandStructsInExpression(csn, { drillRef: true });
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
throwWithAnyError();
|
|
156
156
|
|
|
157
157
|
// FIXME: This does something very similar to cloneWithTransformations -> refactor?
|
|
158
158
|
const transformCsn = transformUtils.transformModel;
|
|
@@ -167,7 +167,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
167
167
|
|
|
168
168
|
if(doA2J) {
|
|
169
169
|
// Expand a structured thing in: keys, columns, order by, group by
|
|
170
|
-
expansion.expandStructureReferences(csn, options, pathDelimiter, {error, info,
|
|
170
|
+
expansion.expandStructureReferences(csn, options, pathDelimiter, {error, info, throwWithAnyError});
|
|
171
171
|
bindCsnReference();
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -353,7 +353,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
353
353
|
if(doA2J)
|
|
354
354
|
flattening.removeLeadingSelf(csn);
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
throwWithAnyError();
|
|
357
357
|
|
|
358
358
|
timetrace.stop();
|
|
359
359
|
|
|
@@ -381,7 +381,22 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
381
381
|
// Set when we turn UUID into String, checked during generateDraftForHana
|
|
382
382
|
'$renamed': killProp,
|
|
383
383
|
// Set when we remove .key from temporal things, used in localized.js
|
|
384
|
-
'$key': killProp
|
|
384
|
+
'$key': killProp,
|
|
385
|
+
// We need .elements easily for rendering - otherwise we have to compute it then
|
|
386
|
+
// Does not fit in the "killers" theme - TODO: Find a better place
|
|
387
|
+
SET: (parent, prop, SET) => {
|
|
388
|
+
if(!SET.elements) {
|
|
389
|
+
const stack = [parent];
|
|
390
|
+
while(stack.length > 0) {
|
|
391
|
+
const query = stack.pop();
|
|
392
|
+
|
|
393
|
+
if(query.SET)
|
|
394
|
+
stack.push(query.SET.args[0]);
|
|
395
|
+
else if(query.SELECT)
|
|
396
|
+
setProp(SET, 'elements', query.SELECT.elements);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
385
400
|
}
|
|
386
401
|
|
|
387
402
|
applyTransformations(csn, killers, [], { skipIgnore: false});
|
|
@@ -393,7 +408,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
393
408
|
/* ----------------------------------- Functions start here -----------------------------------------------*/
|
|
394
409
|
|
|
395
410
|
function bindCsnReference(){
|
|
396
|
-
({ error, warning, info, message,
|
|
411
|
+
({ error, warning, info, message, throwWithAnyError } = makeMessageFunction(csn, options, moduleName));
|
|
397
412
|
({ artifactRef, inspectRef, effectiveType, getFinalBaseType, get$combined } = getUtils(csn));
|
|
398
413
|
({ addDefaultTypeFacets, expandStructsInExpression } = transformUtils.getTransformers(csn, options, pathDelimiter));
|
|
399
414
|
}
|
|
@@ -448,7 +463,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
448
463
|
// get$combined also includes elements which are part of "excluding {}"
|
|
449
464
|
// this shouldn't be an issue here, as such references get rejected
|
|
450
465
|
const elementsOfQuerySources = get$combined(query);
|
|
451
|
-
|
|
466
|
+
forEach(elementsOfQuerySources, (id, element) => {
|
|
452
467
|
// if the ref points to an element which is not explicitly exposed in the column list,
|
|
453
468
|
// but through the '*' operator -> replace the $projection / $self with the correct source entity
|
|
454
469
|
if(id === columnToReplace)
|
|
@@ -458,7 +473,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
458
473
|
|
|
459
474
|
// No implicit CAST in on-condition
|
|
460
475
|
if(replaceWith && replaceWith.cast) {
|
|
461
|
-
const clone =
|
|
476
|
+
const clone = cloneCsnNonDict(replaceWith, options);
|
|
462
477
|
delete clone.cast;
|
|
463
478
|
return clone;
|
|
464
479
|
}
|
|
@@ -475,10 +490,14 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
475
490
|
if (!artifact._ignore) {
|
|
476
491
|
// Do things specific for entities and views (pass 2)
|
|
477
492
|
if ((artifact.kind === 'entity') && artifact.query) {
|
|
478
|
-
|
|
479
|
-
transformEntityOrViewPass2(
|
|
480
|
-
replaceAssociationsInGroupByOrderBy(
|
|
481
|
-
|
|
493
|
+
const process = (parent, prop, query, path) => {
|
|
494
|
+
transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop))
|
|
495
|
+
replaceAssociationsInGroupByOrderBy(parent, options, inspectRef, error, path.concat(prop));
|
|
496
|
+
return query;
|
|
497
|
+
}
|
|
498
|
+
applyTransformationsOnNonDictionary(csn.definitions, artifactName, {
|
|
499
|
+
SELECT: process
|
|
500
|
+
}, {}, [ 'definitions']);
|
|
482
501
|
}
|
|
483
502
|
}
|
|
484
503
|
}
|
|
@@ -618,7 +637,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
618
637
|
|
|
619
638
|
function handleAssocToJoins() {
|
|
620
639
|
// With flattening errors, it makes little sense to continue.
|
|
621
|
-
|
|
640
|
+
throwWithAnyError();
|
|
622
641
|
// the augmentor isn't able to deal with technical configurations and since assoc2join can ignore it we
|
|
623
642
|
// simply make it invisible and copy it over to the result csn
|
|
624
643
|
forEachDefinition(csn, art => art.technicalConfig && setProp(art, 'technicalConfig', art.technicalConfig));
|
|
@@ -998,24 +1017,22 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
|
|
|
998
1017
|
// (which can currently only be 'positiveInteger') and (optional) the value is in a given range
|
|
999
1018
|
function checkTypeParamValue(node, paramName, range = null, path = null) {
|
|
1000
1019
|
const paramValue = node[paramName];
|
|
1001
|
-
if (paramValue
|
|
1020
|
+
if (paramValue === undefined || paramValue === null) {
|
|
1002
1021
|
if(options.toSql || artifact.query || !['cds.Binary','cds.hana.BINARY', 'cds.hana.NCHAR','cds.hana.CHAR'].includes(node.type)) {
|
|
1003
1022
|
return true;
|
|
1004
1023
|
} else {
|
|
1005
|
-
return error('missing-
|
|
1024
|
+
return error('type-missing-argument', path, { name: paramName, id: node.type, $reviewed: false });
|
|
1006
1025
|
}
|
|
1007
1026
|
}
|
|
1008
1027
|
if (range) {
|
|
1009
1028
|
if (isMaxParameterLengthRestricted(node.type) && range.max && paramValue > range.max) {
|
|
1010
|
-
error(
|
|
1011
|
-
{ prop: paramName, type: node.type, number: range.max, $reviewed: false }
|
|
1012
|
-
'Expecting parameter $(PROP) for type $(TYPE) to not exceed $(NUMBER)');
|
|
1029
|
+
error('type-unexpected-argument', path,
|
|
1030
|
+
{ '#': 'max', prop: paramName, type: node.type, number: range.max, $reviewed: false });
|
|
1013
1031
|
return false;
|
|
1014
1032
|
}
|
|
1015
1033
|
if (range.min && paramValue < range.min) {
|
|
1016
|
-
error(
|
|
1017
|
-
{ prop: paramName, type: node.type, number: range.min, $reviewed: false }
|
|
1018
|
-
'Expecting parameter $(PROP) for type $(TYPE) to be greater than or equal to $(NUMBER)');
|
|
1034
|
+
error('type-unexpected-argument', path,
|
|
1035
|
+
{ '#': 'min', prop: paramName, type: node.type, number: range.min, $reviewed: false });
|
|
1019
1036
|
return false;
|
|
1020
1037
|
}
|
|
1021
1038
|
}
|
|
@@ -4,7 +4,7 @@ const { makeMessageFunction } = require('../base/messages');
|
|
|
4
4
|
const { isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
|
|
5
5
|
const transformUtils = require('./transformUtilsNew');
|
|
6
6
|
const { getUtils,
|
|
7
|
-
|
|
7
|
+
cloneCsnNonDict,
|
|
8
8
|
forEachDefinition,
|
|
9
9
|
forEachMemberRecursively,
|
|
10
10
|
applyTransformationsOnNonDictionary,
|
|
@@ -17,14 +17,12 @@ const { getUtils,
|
|
|
17
17
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
18
18
|
const validate = require('../checks/validator');
|
|
19
19
|
const { isArtifactInSomeService, isLocalizedArtifactInService } = require('./odata/utils');
|
|
20
|
-
const ReferenceFlattener = require('./odata/referenceFlattener');
|
|
21
|
-
const { flattenCSN } = require('./odata/structureFlattener');
|
|
22
|
-
const generateForeignKeys = require('./odata/generateForeignKeyElements');
|
|
23
|
-
const expandStructKeysInAssociations = require('./odata/expandStructKeysInAssociations');
|
|
24
20
|
const expandToFinalBaseType = require('./odata/toFinalBaseType');
|
|
25
21
|
const { timetrace } = require('../utils/timetrace');
|
|
26
|
-
const { attachPath } = require('./odata/attachPath');
|
|
27
22
|
const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
|
|
23
|
+
const flattening = require('./db/flattening');
|
|
24
|
+
const associations = require('./db/associations')
|
|
25
|
+
const expansion = require('./db/expansion');
|
|
28
26
|
const generateDrafts = require('./draft/odata');
|
|
29
27
|
|
|
30
28
|
const { addLocalizationViews } = require('./localized');
|
|
@@ -74,10 +72,10 @@ module.exports = { transform4odataWithCsn };
|
|
|
74
72
|
function transform4odataWithCsn(inputModel, options) {
|
|
75
73
|
timetrace.start('OData transformation');
|
|
76
74
|
// copy the model as we don't want to change the input model
|
|
77
|
-
let csn =
|
|
75
|
+
let csn = cloneCsnNonDict(inputModel, options);
|
|
78
76
|
|
|
79
|
-
const { message, error, warning, info,
|
|
80
|
-
|
|
77
|
+
const { message, error, warning, info, throwWithAnyError } = makeMessageFunction(csn, options, 'for.odata');
|
|
78
|
+
throwWithAnyError();
|
|
81
79
|
|
|
82
80
|
// the new transformer works only with new CSN
|
|
83
81
|
checkCSNVersion(csn, options);
|
|
@@ -97,7 +95,6 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
97
95
|
getServiceName,
|
|
98
96
|
isAssocOrComposition,
|
|
99
97
|
isAssociation,
|
|
100
|
-
isStructured,
|
|
101
98
|
inspectRef,
|
|
102
99
|
artifactRef,
|
|
103
100
|
effectiveType,
|
|
@@ -127,13 +124,13 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
127
124
|
|
|
128
125
|
addLocalizationViews(csn, options, acceptLocalizedView);
|
|
129
126
|
|
|
130
|
-
validate.forOdata(csn, {
|
|
127
|
+
const cleanup = validate.forOdata(csn, {
|
|
131
128
|
message, error, warning, info, inspectRef, effectiveType, artifactRef, csn, options, csnUtils, services, getFinalBaseType, isAspect, isExternalServiceMember
|
|
132
129
|
});
|
|
133
130
|
|
|
134
131
|
|
|
135
132
|
// Throw exception in case of errors
|
|
136
|
-
|
|
133
|
+
throwWithAnyError();
|
|
137
134
|
|
|
138
135
|
// Semantic checks before flattening regarding temporal data
|
|
139
136
|
// TODO: Move in the validator
|
|
@@ -155,35 +152,38 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
155
152
|
// Check if structured elements and managed associations are compared in an expression
|
|
156
153
|
// and expand these structured elements. This tuple expansion allows all other
|
|
157
154
|
// subsequent procession steps (especially a2j) to see plain paths in expressions.
|
|
158
|
-
// If errors are detected,
|
|
155
|
+
// If errors are detected, throwWithAnyError() will return from further processing
|
|
159
156
|
expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
|
|
160
157
|
|
|
161
|
-
// handles reference flattening
|
|
162
|
-
let referenceFlattener = new ReferenceFlattener();
|
|
163
|
-
referenceFlattener.resolveAllReferences(csn, inspectRef, isStructured);
|
|
164
|
-
attachPath(csn);
|
|
165
|
-
|
|
166
|
-
referenceFlattener.applyAliasesInOnCond(csn, inspectRef);
|
|
167
|
-
|
|
168
158
|
if (!structuredOData) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
159
|
+
expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, { skipArtifact: isExternalServiceMember });
|
|
160
|
+
const resolved = new WeakMap();
|
|
161
|
+
// No refs with struct-steps exist anymore
|
|
162
|
+
flattening.flattenAllStructStepsInRefs(csn, options, resolved, '_', { skipArtifact: isExternalServiceMember });
|
|
163
|
+
// No type references exist anymore
|
|
164
|
+
// Needs to happen exactly between flattenAllStructStepsInRefs and flattenElements to keep model resolvable.
|
|
165
|
+
// OData doesn't resolve type chains after the first 'items'
|
|
166
|
+
flattening.resolveTypeReferences(csn, options, resolved, '_',
|
|
167
|
+
{ skip: [ 'action', 'aspect', 'event', 'function', 'type'], skipArtifact: isExternalServiceMember, skipStandard: { items: true } });
|
|
168
|
+
// No structured elements exists anymore
|
|
169
|
+
flattening.flattenElements(csn, options, '_', error,
|
|
170
|
+
{ skip: ['action', 'aspect', 'event', 'function', 'type'], skipArtifact: isExternalServiceMember,
|
|
171
|
+
skipStandard: { items: true }, // don't drill further into .items
|
|
172
|
+
skipDict: { actions: true } }); // don't drill further into .actions -> bound actions, action-artifacts are handled by skip
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
//
|
|
177
|
-
|
|
175
|
+
// TODO: add the generated foreign keys to the columns when we are in a view
|
|
176
|
+
// see db/views.js::addForeignKeysToColumns
|
|
177
|
+
flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, '_', !structuredOData, { skipArtifact: isExternalServiceMember });
|
|
178
178
|
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
//
|
|
186
|
-
|
|
179
|
+
// Allow using managed associations as steps in on-conditions to access their fks
|
|
180
|
+
// To be done after handleManagedAssociationsAndCreateForeignKeys,
|
|
181
|
+
// since then the foreign keys of the managed assocs are part of the elements
|
|
182
|
+
if(!structuredOData)
|
|
183
|
+
forEachDefinition(csn, associations.getManagedAssocStepsInOnConditionFinalizer(csn, '_'));
|
|
184
|
+
|
|
185
|
+
// structure flattener reports errors, further processing is not safe -> throw exception in case of errors
|
|
186
|
+
throwWithAnyError();
|
|
187
187
|
|
|
188
188
|
// Apply default type facets as set by options
|
|
189
189
|
// Flatten on-conditions in unmanaged associations
|
|
@@ -207,22 +207,23 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
207
207
|
generateDrafts(csn, options, services)
|
|
208
208
|
|
|
209
209
|
// Deal with all kind of annotations manipulations here
|
|
210
|
+
const skipPersNameKinds = {'service':1, 'context':1, 'namespace':1, 'annotation':1, 'action':1, 'function':1};
|
|
210
211
|
forEachDefinition(csn, (def, defName) => {
|
|
211
212
|
// Resolve annotation shorthands for entities, types, annotations, ...
|
|
212
213
|
renameShorthandAnnotations(def);
|
|
213
214
|
|
|
214
215
|
// Annotate artifacts with their DB names if requested.
|
|
215
216
|
// Skip artifacts that have no DB equivalent anyway
|
|
216
|
-
if (options.toOdata.names && !
|
|
217
|
+
if (options.toOdata.names && !(def.kind in skipPersNameKinds))
|
|
217
218
|
def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.toOdata.names, csn);
|
|
218
219
|
|
|
219
|
-
forEachMemberRecursively(def, (member, memberName, propertyName
|
|
220
|
+
forEachMemberRecursively(def, (member, memberName, propertyName) => {
|
|
220
221
|
// Annotate elements, foreign keys, parameters, etc. with their DB names if requested
|
|
221
222
|
// Only these are actually required and don't annotate virtual elements in entities or types
|
|
222
223
|
// as they have no DB representation (although in views)
|
|
223
|
-
if (options.toOdata.names && typeof member === 'object' && !
|
|
224
|
+
if (options.toOdata.names && typeof member === 'object' && !(member.kind === 'action' || member.kind === 'function') && propertyName !== 'enum' && (!member.virtual || def.query)) {
|
|
224
225
|
// If we have a 'preserved dotted name' (i.e. we are a result of flattening), use that for the @cds.persistence.name annotation
|
|
225
|
-
member['@cds.persistence.name'] = getElementDatabaseNameOf(
|
|
226
|
+
member['@cds.persistence.name'] = getElementDatabaseNameOf(member._flatElementNameWithDots || memberName, options.toOdata.names);
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
// Mark fields with @odata.on.insert/update as @Core.Computed
|
|
@@ -252,9 +253,9 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
252
253
|
}, { skipArtifact: isExternalServiceMember })
|
|
253
254
|
|
|
254
255
|
// Throw exception in case of errors
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (options.testMode) csn =
|
|
256
|
+
throwWithAnyError();
|
|
257
|
+
cleanup();
|
|
258
|
+
if (options.testMode) csn = cloneCsnNonDict(csn, options); // sort, keep hidden properties
|
|
258
259
|
timetrace.stop();
|
|
259
260
|
return csn;
|
|
260
261
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
const { makeMessageFunction } = require('../base/messages');
|
|
4
4
|
const { setProp } = require('../base/model');
|
|
5
5
|
const { hasErrors } = require('../base/messages');
|
|
6
|
-
const { cloneCsnDictionary } = require('../model/csnUtils');
|
|
6
|
+
const { cloneCsnDictionary, applyDefinitionAnnotationsFromExtensions} = require('../model/csnUtils');
|
|
7
7
|
const { cleanSymbols } = require('../base/cleanSymbols.js');
|
|
8
8
|
const {
|
|
9
|
-
|
|
9
|
+
cloneCsnNonDict,
|
|
10
10
|
forEachDefinition,
|
|
11
11
|
forEachGeneric,
|
|
12
12
|
forAllQueries,
|
|
@@ -86,6 +86,12 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
|
|
|
86
86
|
|
|
87
87
|
forEachDefinition(csn, definition => cleanSymbols(definition, _hasLocalizedView, _isViewForEntity, _isViewForView, _targetFor));
|
|
88
88
|
|
|
89
|
+
// In case that the user tried to annotate `localized.*` artifacts, apply them.
|
|
90
|
+
applyDefinitionAnnotationsFromExtensions(csn, {
|
|
91
|
+
overwrite: true,
|
|
92
|
+
filter: (name) => name.startsWith('localized.')
|
|
93
|
+
});
|
|
94
|
+
|
|
89
95
|
sortCsnDefinitionsForTests(csn, options);
|
|
90
96
|
return csn;
|
|
91
97
|
|
|
@@ -141,9 +147,8 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
|
|
|
141
147
|
else
|
|
142
148
|
view = createLocalizedViewForEntity(art, artName, textElements);
|
|
143
149
|
|
|
150
|
+
copyPersistenceAnnotations(view, art);
|
|
144
151
|
csn.definitions[viewName] = view;
|
|
145
|
-
|
|
146
|
-
copyPersistenceAnnotations(csn.definitions[viewName], art);
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
/**
|
|
@@ -245,9 +250,9 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
|
|
|
245
250
|
};
|
|
246
251
|
|
|
247
252
|
if (view.query)
|
|
248
|
-
convenienceView.query =
|
|
253
|
+
convenienceView.query = cloneCsnNonDict(view.query, options);
|
|
249
254
|
else if (view.projection)
|
|
250
|
-
convenienceView.projection =
|
|
255
|
+
convenienceView.projection = cloneCsnNonDict(view.projection, options);
|
|
251
256
|
|
|
252
257
|
convenienceView.elements = cloneCsnDictionary(view.elements, options);
|
|
253
258
|
convenienceView[_isViewForView] = true;
|
|
@@ -549,7 +554,7 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
|
|
|
549
554
|
if (!obj || typeof obj !== 'object' || Array.isArray(obj))
|
|
550
555
|
return;
|
|
551
556
|
|
|
552
|
-
for (const prop of [ 'ref', 'target'
|
|
557
|
+
for (const prop of [ 'ref', 'target' ]) {
|
|
553
558
|
const val = obj[prop];
|
|
554
559
|
if (prop === 'ref') {
|
|
555
560
|
rewriteRefToLocalized(obj);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
forEachDefinition, forEachMemberRecursively,
|
|
5
|
-
isBuiltinType, cloneCsnDictionary,
|
|
5
|
+
isBuiltinType, cloneCsnDictionary, cloneCsnNonDict,
|
|
6
6
|
} = require('../../model/csnUtils');
|
|
7
7
|
const { isArtifactInSomeService, isArtifactInService } = require('./utils');
|
|
8
8
|
|
|
@@ -97,7 +97,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
97
97
|
// type T: S; --> Integer;
|
|
98
98
|
// type S: X; --> Integer;
|
|
99
99
|
// type X: Integer;
|
|
100
|
-
//
|
|
100
|
+
//
|
|
101
101
|
// type A: B; -> {...}
|
|
102
102
|
// type B: C; -> { ... }
|
|
103
103
|
// type C { .... };
|
|
@@ -120,7 +120,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
120
120
|
// type T: S; --> Integer;
|
|
121
121
|
// type S: X; --> Integer;
|
|
122
122
|
// type X: Integer;
|
|
123
|
-
//
|
|
123
|
+
//
|
|
124
124
|
// type {
|
|
125
125
|
// struct_elt: many A; ---> stays the same
|
|
126
126
|
// scalar_elt: T; ---> Integer;
|
|
@@ -148,7 +148,9 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
148
148
|
// example in actions: 'action act() return Primitive; type Primitive: array of String;'
|
|
149
149
|
const currService = csnUtils.getServiceName(defName);
|
|
150
150
|
const finalType = csnUtils.getFinalTypeDef(node.type);
|
|
151
|
-
if (finalType.items &&
|
|
151
|
+
if (finalType.items &&
|
|
152
|
+
(isBuiltinType(finalType.items.type) || isBuiltinType(csnUtils.getFinalBaseType(finalType.items.type))))
|
|
153
|
+
{
|
|
152
154
|
if (!isArtifactInService(node.type, currService) || !isV4) {
|
|
153
155
|
node.items = finalType.items;
|
|
154
156
|
delete node.type;
|
|
@@ -162,7 +164,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
162
164
|
// do the clone only if really needed
|
|
163
165
|
if((finalType.items && !node.items) ||
|
|
164
166
|
(finalType.elements && !node.elements))
|
|
165
|
-
clone =
|
|
167
|
+
clone = cloneCsnNonDict({ definitions: { 'TypeDef': finalType } }, options);
|
|
166
168
|
if (finalType.items) {
|
|
167
169
|
delete node.type;
|
|
168
170
|
if(!node.items)
|
|
@@ -193,4 +195,4 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|
|
196
|
-
module.exports = expandToFinalBaseType;
|
|
198
|
+
module.exports = expandToFinalBaseType;
|