@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
@@ -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
+ };