@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.
- package/CHANGELOG.md +136 -0
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +10 -8
- package/bin/cdsc.js +58 -35
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +16 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +10 -36
- package/lib/api/options.js +17 -8
- package/lib/api/validate.js +30 -3
- package/lib/backends.js +12 -13
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +3 -2
- package/lib/base/message-registry.js +64 -11
- package/lib/base/messages.js +38 -18
- package/lib/base/model.js +6 -4
- package/lib/base/optionProcessorHelper.js +148 -86
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +2 -1
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +4 -4
- package/lib/checks/managedInType.js +4 -4
- package/lib/checks/queryNoDbArtifacts.js +1 -3
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/sql-snippets.js +93 -0
- package/lib/checks/unknownMagic.js +6 -3
- package/lib/checks/validator.js +8 -0
- package/lib/compiler/assert-consistency.js +14 -5
- package/lib/compiler/base.js +64 -0
- package/lib/compiler/builtins.js +62 -16
- package/lib/compiler/checks.js +34 -10
- package/lib/compiler/definer.js +91 -112
- package/lib/compiler/index.js +30 -30
- package/lib/compiler/propagator.js +8 -4
- package/lib/compiler/resolver.js +279 -63
- package/lib/compiler/shared.js +65 -230
- package/lib/compiler/utils.js +191 -0
- package/lib/edm/annotations/genericTranslation.js +35 -18
- package/lib/edm/annotations/preprocessAnnotations.js +1 -1
- package/lib/edm/csn2edm.js +4 -3
- package/lib/edm/edm.js +8 -8
- package/lib/edm/edmPreprocessor.js +61 -59
- package/lib/edm/edmUtils.js +14 -15
- package/lib/gen/Dictionary.json +82 -40
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +19 -1
- package/lib/gen/language.tokens +80 -73
- package/lib/gen/languageLexer.interp +27 -1
- package/lib/gen/languageLexer.js +925 -826
- package/lib/gen/languageLexer.tokens +72 -65
- package/lib/gen/languageParser.js +4817 -4102
- package/lib/json/from-csn.js +57 -26
- package/lib/json/to-csn.js +244 -51
- package/lib/language/antlrParser.js +12 -1
- package/lib/language/docCommentParser.js +1 -1
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +106 -30
- package/lib/language/language.g4 +200 -70
- package/lib/language/multiLineStringParser.js +536 -0
- package/lib/main.d.ts +220 -21
- package/lib/main.js +6 -3
- package/lib/model/api.js +2 -2
- package/lib/model/csnRefs.js +218 -86
- package/lib/model/csnUtils.js +99 -178
- package/lib/model/enrichCsn.js +84 -43
- package/lib/model/revealInternalProperties.js +25 -8
- package/lib/model/sortViews.js +8 -1
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +33 -18
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +2 -2
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +202 -82
- package/lib/render/toHdbcds.js +194 -135
- package/lib/render/toRename.js +7 -10
- package/lib/render/toSql.js +91 -51
- package/lib/render/utils/common.js +24 -5
- package/lib/render/utils/sql.js +6 -4
- package/lib/transform/braceExpression.js +4 -2
- package/lib/transform/db/applyTransformations.js +189 -0
- package/lib/transform/db/associations.js +389 -0
- package/lib/transform/db/cdsPersistence.js +150 -0
- package/lib/transform/db/constraints.js +275 -119
- package/lib/transform/db/draft.js +6 -4
- package/lib/transform/db/expansion.js +10 -9
- package/lib/transform/db/flattening.js +23 -8
- package/lib/transform/db/temporal.js +236 -0
- package/lib/transform/db/transformExists.js +106 -25
- package/lib/transform/db/views.js +485 -0
- package/lib/transform/forHanaNew.js +90 -1036
- package/lib/transform/forOdataNew.js +11 -3
- package/lib/transform/localized.js +5 -14
- package/lib/transform/odata/generateForeignKeyElements.js +2 -2
- package/lib/transform/transformUtilsNew.js +34 -20
- package/lib/transform/translateAssocsToJoins.js +15 -23
- package/lib/transform/universalCsnEnricher.js +217 -47
- package/lib/utils/file.js +13 -6
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +55 -27
- package/package.json +1 -1
- package/lib/transform/db/helpers.js +0 -58
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
forEachGeneric, forEachMemberRecursively, hasAnnotationValue, isPersistedOnDatabase,
|
|
5
|
+
getUtils,
|
|
6
|
+
} = require('../../model/csnUtils');
|
|
7
|
+
const transformUtils = require('../transformUtilsNew');
|
|
8
|
+
|
|
9
|
+
const exists = '@cds.persistence.exists';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Return a callback function for forEachDefinition that marks artifacts that are abstract or @cds.persistence.exists/skip
|
|
13
|
+
* with _ignore.
|
|
14
|
+
*
|
|
15
|
+
* @returns {(artifact: CSN.Artifact, artifactName) => void} Callback function for forEachDefinition
|
|
16
|
+
*/
|
|
17
|
+
function getAnnoProcessor() {
|
|
18
|
+
return handleCdsPersistence;
|
|
19
|
+
/**
|
|
20
|
+
* @param {CSN.Artifact} artifact
|
|
21
|
+
*/
|
|
22
|
+
function handleCdsPersistence(artifact) {
|
|
23
|
+
const ignoreArtifact = (artifact.kind === 'entity' || artifact.kind === 'view') &&
|
|
24
|
+
(artifact.abstract ||
|
|
25
|
+
hasAnnotationValue(artifact, '@cds.persistence.skip') ||
|
|
26
|
+
hasAnnotationValue(artifact, exists));
|
|
27
|
+
if (ignoreArtifact)
|
|
28
|
+
artifact._ignore = true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Return a callback function for forEachDefinition that marks associations with _ignore
|
|
34
|
+
* if their target does not reach the database, i.e. marked with @cds.persistence.skip or is abstract
|
|
35
|
+
*
|
|
36
|
+
* @param {CSN.Model} csn
|
|
37
|
+
* @param {CSN.Options} options
|
|
38
|
+
* @param {object} messageFunctions
|
|
39
|
+
* @param {Function} messageFunctions.info
|
|
40
|
+
* @returns {(artifact: CSN.Artifact, artifactName: string, prop: string, path: CSN.Path) => void} Callback function for forEachDefinition
|
|
41
|
+
*/
|
|
42
|
+
function getAssocToSkippedIgnorer(csn, options, messageFunctions) {
|
|
43
|
+
const { info } = messageFunctions;
|
|
44
|
+
const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
|
|
45
|
+
|
|
46
|
+
const { isAssocOrComposition } = getUtils(csn);
|
|
47
|
+
|
|
48
|
+
return ignoreAssociationToSkippedTarget;
|
|
49
|
+
/**
|
|
50
|
+
* Associations that target a @cds.persistence.skip artifact must be removed
|
|
51
|
+
* from the persistence model
|
|
52
|
+
*
|
|
53
|
+
* @param {CSN.Artifact} artifact
|
|
54
|
+
* @param {string} artifactName
|
|
55
|
+
* @param {string} prop
|
|
56
|
+
* @param {CSN.Path} path
|
|
57
|
+
*/
|
|
58
|
+
function ignoreAssociationToSkippedTarget(artifact, artifactName, prop, path) {
|
|
59
|
+
if (isPersistedOnDatabase(artifact)) {
|
|
60
|
+
// TODO: structure in CSN is artifact.query.[SELECT/SET].mixin
|
|
61
|
+
if (artifact.query) {
|
|
62
|
+
// If we do A2J, we don't need to check the mixin. Either it is used -> a join
|
|
63
|
+
// or published -> handled via elements/members. Unused mixins are removed anyway.
|
|
64
|
+
if (!doA2J && artifact.query.SELECT && artifact.query.SELECT.mixin)
|
|
65
|
+
forEachGeneric(artifact.query.SELECT, 'mixin', ignore, path.concat([ 'query', 'SELECT' ]));
|
|
66
|
+
|
|
67
|
+
else if (!doA2J && artifact.query.SET && artifact.query.SET.mixin)
|
|
68
|
+
forEachGeneric(artifact.query.SET, 'mixin', ignore, path.concat([ 'query', 'SET' ]));
|
|
69
|
+
}
|
|
70
|
+
forEachMemberRecursively(artifact, ignore, [ 'definitions', artifactName ]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Mark the given member with _ignore if it is an association/composition and it's target is unreachable.
|
|
76
|
+
*
|
|
77
|
+
* @param {CSN.Element} member
|
|
78
|
+
* @param {string} memberName
|
|
79
|
+
* @param {string} prop
|
|
80
|
+
* @param {CSN.Path} path
|
|
81
|
+
* @todo Why do we check for @cds.persistence.exists here if the parent-function only calls this for skip/abstract?
|
|
82
|
+
*/
|
|
83
|
+
function ignore(member, memberName, prop, path) {
|
|
84
|
+
if (options.sqlDialect === 'hana' && !member._ignore && member.target && isAssocOrComposition(member.type) && isUnreachableAssociationTarget(csn.definitions[member.target])) {
|
|
85
|
+
const targetAnnotation = hasAnnotationValue(csn.definitions[member.target], exists) ? exists : '@cds.persistence.skip';
|
|
86
|
+
info(null, path,
|
|
87
|
+
{ target: member.target, anno: targetAnnotation },
|
|
88
|
+
'Association has been removed as it\'s target $(TARGET) is annotated with $(ANNO)');
|
|
89
|
+
member._ignore = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check wether the given artifact is an unreachable association target because it will not "realy" hit the database:
|
|
95
|
+
* - @cds.persistence.skip/exists
|
|
96
|
+
* - abstract
|
|
97
|
+
*
|
|
98
|
+
* @param {CSN.Artifact} art
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
function isUnreachableAssociationTarget(art) {
|
|
102
|
+
return !isPersistedOnDatabase(art) || hasAnnotationValue(art, exists);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Return a callback function for forEachDefinition that handles artifacts marked with @cds.persistence.table.
|
|
108
|
+
* If a .query artifact has this annotation, the .query will be deleted and it will be treated like a table.
|
|
109
|
+
*
|
|
110
|
+
* @param {CSN.Model} csn
|
|
111
|
+
* @param {CSN.Options} options
|
|
112
|
+
* @param {object} messageFunctions
|
|
113
|
+
* @param {Function} messageFunctions.error
|
|
114
|
+
* @returns {(artifact: CSN.Artifact, artifactName) => void} Callback function for forEachDefinition
|
|
115
|
+
*/
|
|
116
|
+
function getPersistenceTableProcessor(csn, options, messageFunctions ) {
|
|
117
|
+
const { error } = messageFunctions;
|
|
118
|
+
const {
|
|
119
|
+
recurseElements,
|
|
120
|
+
} = transformUtils.getTransformers(csn, options, '_');
|
|
121
|
+
|
|
122
|
+
return handleQueryish;
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {CSN.Artifact} artifact
|
|
127
|
+
* @param {string} artifactName
|
|
128
|
+
*/
|
|
129
|
+
function handleQueryish(artifact, artifactName) {
|
|
130
|
+
const stripQueryish = artifact.query && hasAnnotationValue(artifact, '@cds.persistence.table');
|
|
131
|
+
|
|
132
|
+
if (stripQueryish) {
|
|
133
|
+
artifact.kind = 'entity';
|
|
134
|
+
delete artifact.query;
|
|
135
|
+
|
|
136
|
+
recurseElements(artifact, [ 'definitions', artifactName ], (member, path) => {
|
|
137
|
+
// All elements must have a type for this to work
|
|
138
|
+
if (!member._ignore && !member.kind && !member.type)
|
|
139
|
+
error(null, path, 'Expecting element to have a type if view is annotated with “@cds.persistence.table“');
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
getAnnoProcessor,
|
|
148
|
+
getAssocToSkippedIgnorer,
|
|
149
|
+
getPersistenceTableProcessor,
|
|
150
|
+
};
|