@sap/cds-compiler 2.12.0 → 2.13.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +110 -15
  2. package/bin/cdsc.js +13 -13
  3. package/bin/cdsse.js +2 -2
  4. package/doc/CHANGELOG_BETA.md +13 -6
  5. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  6. package/doc/NameResolution.md +21 -16
  7. package/lib/api/main.js +28 -63
  8. package/lib/api/options.js +3 -3
  9. package/lib/api/validate.js +0 -5
  10. package/lib/backends.js +15 -23
  11. package/lib/base/dictionaries.js +0 -8
  12. package/lib/base/error.js +26 -0
  13. package/lib/base/keywords.js +7 -17
  14. package/lib/base/location.js +9 -4
  15. package/lib/base/message-registry.js +25 -4
  16. package/lib/base/messages.js +16 -26
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +158 -123
  19. package/lib/checks/annotationsOData.js +1 -1
  20. package/lib/checks/cdsPersistence.js +2 -1
  21. package/lib/checks/enricher.js +17 -1
  22. package/lib/checks/invalidTarget.js +3 -1
  23. package/lib/checks/managedWithoutKeys.js +3 -1
  24. package/lib/checks/selectItems.js +4 -4
  25. package/lib/checks/sql-snippets.js +27 -26
  26. package/lib/checks/types.js +1 -1
  27. package/lib/checks/validator.js +4 -7
  28. package/lib/compiler/assert-consistency.js +5 -3
  29. package/lib/compiler/builtins.js +8 -6
  30. package/lib/compiler/checks.js +14 -3
  31. package/lib/compiler/cycle-detector.js +1 -1
  32. package/lib/compiler/define.js +1103 -0
  33. package/lib/compiler/extend.js +983 -0
  34. package/lib/compiler/finalize-parse-cdl.js +231 -0
  35. package/lib/compiler/index.js +32 -13
  36. package/lib/compiler/kick-start.js +190 -0
  37. package/lib/compiler/moduleLayers.js +4 -4
  38. package/lib/compiler/populate.js +1226 -0
  39. package/lib/compiler/propagator.js +111 -46
  40. package/lib/compiler/resolve.js +1433 -0
  41. package/lib/compiler/shared.js +64 -37
  42. package/lib/compiler/tweak-assocs.js +529 -0
  43. package/lib/compiler/utils.js +197 -33
  44. package/lib/edm/.eslintrc.json +5 -0
  45. package/lib/edm/annotations/genericTranslation.js +5 -9
  46. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  47. package/lib/edm/csn2edm.js +9 -8
  48. package/lib/edm/edm.js +11 -12
  49. package/lib/edm/edmPreprocessor.js +137 -73
  50. package/lib/edm/edmUtils.js +116 -22
  51. package/lib/gen/Dictionary.json +10 -3
  52. package/lib/gen/language.checksum +1 -1
  53. package/lib/gen/language.interp +9 -1
  54. package/lib/gen/language.tokens +86 -83
  55. package/lib/gen/languageLexer.interp +10 -1
  56. package/lib/gen/languageLexer.js +860 -833
  57. package/lib/gen/languageLexer.tokens +78 -75
  58. package/lib/gen/languageParser.js +5282 -4265
  59. package/lib/json/from-csn.js +12 -1
  60. package/lib/json/to-csn.js +126 -66
  61. package/lib/language/docCommentParser.js +2 -2
  62. package/lib/language/genericAntlrParser.js +76 -3
  63. package/lib/language/language.g4 +297 -130
  64. package/lib/language/multiLineStringParser.js +5 -5
  65. package/lib/main.d.ts +468 -59
  66. package/lib/main.js +35 -9
  67. package/lib/model/api.js +3 -1
  68. package/lib/model/csnRefs.js +225 -156
  69. package/lib/model/csnUtils.js +192 -223
  70. package/lib/model/enrichCsn.js +70 -29
  71. package/lib/model/revealInternalProperties.js +27 -6
  72. package/lib/model/sortViews.js +2 -1
  73. package/lib/modelCompare/compare.js +17 -12
  74. package/lib/optionProcessor.js +5 -4
  75. package/lib/render/manageConstraints.js +35 -32
  76. package/lib/render/toCdl.js +73 -288
  77. package/lib/render/toHdbcds.js +25 -23
  78. package/lib/render/toSql.js +98 -41
  79. package/lib/render/utils/common.js +5 -10
  80. package/lib/render/utils/sql.js +4 -3
  81. package/lib/render/utils/stringEscapes.js +111 -0
  82. package/lib/sql-identifier.js +1 -1
  83. package/lib/transform/.eslintrc.json +5 -0
  84. package/lib/transform/db/.eslintrc.json +2 -0
  85. package/lib/transform/db/applyTransformations.js +35 -12
  86. package/lib/transform/db/assertUnique.js +1 -1
  87. package/lib/transform/db/associations.js +103 -305
  88. package/lib/transform/db/cdsPersistence.js +2 -2
  89. package/lib/transform/db/constraints.js +55 -52
  90. package/lib/transform/db/expansion.js +46 -24
  91. package/lib/transform/db/flattening.js +553 -102
  92. package/lib/transform/db/groupByOrderBy.js +3 -1
  93. package/lib/transform/db/transformExists.js +59 -6
  94. package/lib/transform/db/views.js +5 -4
  95. package/lib/transform/draft/.eslintrc.json +38 -0
  96. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  97. package/lib/transform/draft/odata.js +227 -0
  98. package/lib/transform/forHanaNew.js +67 -183
  99. package/lib/transform/forOdataNew.js +17 -171
  100. package/lib/transform/localized.js +34 -19
  101. package/lib/transform/odata/generateForeignKeyElements.js +1 -1
  102. package/lib/transform/odata/referenceFlattener.js +95 -89
  103. package/lib/transform/odata/structureFlattener.js +1 -1
  104. package/lib/transform/odata/toFinalBaseType.js +86 -12
  105. package/lib/transform/odata/typesExposure.js +5 -5
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +36 -22
  108. package/lib/transform/translateAssocsToJoins.js +2 -19
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +170 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/objectUtils.js +30 -0
  114. package/package.json +1 -1
  115. package/share/messages/README.md +26 -0
  116. package/lib/compiler/definer.js +0 -2361
  117. package/lib/compiler/resolver.js +0 -3079
  118. package/lib/transform/universalCsnEnricher.js +0 -237
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const { csnRefs } = require('../model/csnRefs');
3
+ const { csnRefs, implicitAs } = require('../model/csnRefs');
4
4
  const { applyTransformations, applyTransformationsOnNonDictionary } = require('../transform/db/applyTransformations');
5
5
  const { isBuiltinType } = require('../compiler/builtins.js')
6
6
  const { sortCsn, cloneCsnDictionary: _cloneCsnDictionary } = require('../json/to-csn');
7
+ const { ModelError } = require("../base/error");
7
8
  const version = require('../../package.json').version;
8
9
 
9
10
  // Low-level utility functions to work with compact CSN.
@@ -36,15 +37,15 @@ const version = require('../../package.json').version;
36
37
  * Get utility functions for a given CSN.
37
38
  * @param {CSN.Model} model (Compact) CSN model
38
39
  */
39
- function getUtils(model) {
40
- const { artifactRef, inspectRef, effectiveType, getOrigin } = csnRefs(model);
40
+ function getUtils(model, universalReady) {
41
+ const { artifactRef, inspectRef, effectiveType, getOrigin, targetAspect, getColumn, getElement, initDefinition } = csnRefs(model, universalReady);
41
42
 
42
43
  return {
43
44
  getCsnDef,
44
45
  isStructured,
45
46
  getFinalType,
46
47
  getFinalTypeDef,
47
- isManagedAssociationElement,
48
+ isManagedAssociation,
48
49
  isAssocOrComposition,
49
50
  isAssociation,
50
51
  isComposition,
@@ -62,6 +63,10 @@ function getUtils(model) {
62
63
  get$combined,
63
64
  getOrigin,
64
65
  getQueryPrimarySource,
66
+ targetAspect,
67
+ getColumn,
68
+ getElement,
69
+ initDefinition
65
70
  };
66
71
 
67
72
  /**
@@ -71,125 +76,125 @@ function getUtils(model) {
71
76
  * @returns {object}
72
77
  */
73
78
  function get$combined(query) {
74
- const sources = getSources(query);
75
- return sources;
79
+ return getSources(query);
80
+ }
76
81
 
77
- /**
78
- * Get the union of all elements from the from clause
79
- * - descend into unions, following the lead query
80
- * - merge all queries in case of joins
81
- * - follow subqueries
82
- *
83
- * @param {CSN.Query} query Query to check
84
- * @returns {object} Map of sources
85
- */
86
- function getSources(query, isSubquery=false) {
87
- // Remark CW: better just a while along query.SET.args[0]
88
- if (query.SET) {
89
- if (query.SET.args[0].SELECT && query.SET.args[0].SELECT.elements)
90
- return mergeElementsIntoMap(Object.create(null), query.SET.args[0].SELECT.elements, query.SET.args[0].$location);
82
+ /**
83
+ * Get the union of all elements from the from clause
84
+ * - descend into unions, following the lead query
85
+ * - merge all queries in case of joins
86
+ * - follow subqueries
87
+ *
88
+ * @param {CSN.Query} query Query to check
89
+ * @param {boolean} [isSubquery]
90
+ * @returns {object} Map of sources
91
+ */
92
+ function getSources(query, isSubquery=false) {
93
+ // Remark CW: better just a while along query.SET.args[0]
94
+ if (query.SET) {
95
+ if (query.SET.args[0].SELECT && query.SET.args[0].SELECT.elements)
96
+ return mergeElementsIntoMap(Object.create(null), query.SET.args[0].SELECT.elements, query.SET.args[0].$location);
91
97
 
92
- return getSources(query.SET.args[0], isSubquery);
98
+ return getSources(query.SET.args[0], isSubquery);
99
+ }
100
+ else if (query.SELECT) {
101
+ if (query.SELECT.from.args) {
102
+ return walkArgs(query.SELECT.from.args);
93
103
  }
94
- else if (query.SELECT) {
95
- if (query.SELECT.from.args) {
96
- return walkArgs(query.SELECT.from.args);
97
- }
98
- else if (query.SELECT.from.ref) {
99
- let art = artifactRef(query.SELECT.from);
104
+ else if (query.SELECT.from.ref) {
105
+ let art = artifactRef(query.SELECT.from);
100
106
 
101
- if(art.target)
102
- art = artifactRef(art.target);
107
+ if(art.target)
108
+ art = artifactRef(art.target);
103
109
 
104
- if(isSubquery && !query.SELECT.elements)
105
- throw new Error('Expected subquery to have .elements');
110
+ if(isSubquery && !query.SELECT.elements)
111
+ throw new ModelError('Expected subquery to have .elements');
106
112
 
107
- return mergeElementsIntoMap(Object.create(null), isSubquery ? query.SELECT.elements : art.elements, art.$location,
108
- query.SELECT.from.as || query.SELECT.from.ref[query.SELECT.from.ref.length - 1],
109
- query.SELECT.from.ref[query.SELECT.from.ref.length - 1] || query.SELECT.from.as );
110
- }
111
- else if (query.SELECT.from.SET || query.SELECT.from.SELECT) {
112
- return getSources(query.SELECT.from, true);
113
- }
113
+ return mergeElementsIntoMap(Object.create(null), isSubquery ? query.SELECT.elements : art.elements, art.$location,
114
+ query.SELECT.from.as || query.SELECT.from.ref[query.SELECT.from.ref.length - 1],
115
+ query.SELECT.from.ref[query.SELECT.from.ref.length - 1] || query.SELECT.from.as );
114
116
  }
115
-
116
- function walkArgs(args) {
117
- let elements = Object.create(null);
118
- for (const arg of args) {
119
- if (arg.args) {
120
- elements = mergeElementMaps(elements, walkArgs(arg.args));
121
- }
122
- else if (arg.ref) {
123
- const art = artifactRef(arg);
124
- elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || arg.ref[arg.ref.length - 1], arg.ref[arg.ref.length - 1] || arg.as);
125
- }
126
- else if (arg.SELECT || arg.SET) {
127
- elements = mergeElementMaps(elements, getSources(arg));
128
- }
129
- }
130
-
131
- return elements;
117
+ else if (query.SELECT.from.SET || query.SELECT.from.SELECT) {
118
+ return getSources(query.SELECT.from, true);
132
119
  }
120
+ }
133
121
 
134
- return {};
135
-
136
- /**
137
- * Merge two maps of elements together
138
- *
139
- * @param {object} mapA Map a - will be returned
140
- * @param {object} mapB Map b - will not be returned
141
- * @returns {object} mapA
142
- */
143
- function mergeElementMaps(mapA, mapB) {
144
- for (const elementName in mapB) {
145
- if (!mapA[elementName])
146
- mapA[elementName] = [];
147
-
148
- mapB[elementName].forEach(e => mapA[elementName].push(e));
149
- }
122
+ return {};
123
+ }
150
124
 
151
- return mapA;
125
+ function walkArgs(args) {
126
+ let elements = Object.create(null);
127
+ for (const arg of args) {
128
+ if (arg.args) {
129
+ elements = mergeElementMaps(elements, walkArgs(arg.args));
130
+ }
131
+ else if (arg.ref) {
132
+ const art = artifactRef(arg);
133
+ elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || arg.ref[arg.ref.length - 1], arg.ref[arg.ref.length - 1] || arg.as);
134
+ }
135
+ else if (arg.SELECT || arg.SET) {
136
+ elements = mergeElementMaps(elements, getSources(arg));
152
137
  }
138
+ }
153
139
 
154
- /**
155
- * Merge elements into an existing map
156
- *
157
- * @param {any} existingMap map to merge into - will be returned
158
- * @param {object} elements elements to merge into the map
159
- * @param {CSN.Location} $location $location of the elements - where they come from
160
- * @param {any} [parent] Name of the parent of the elements, alias before ref
161
- * @param {any} [error_parent] Parent name to use for error messages, ref before alias
162
- * @returns {object} existingMap
163
- */
164
- function mergeElementsIntoMap(existingMap, elements, $location, parent, error_parent) {
165
- for (const elementName in elements) {
166
- const element = elements[elementName];
167
- if (!existingMap[elementName])
168
- existingMap[elementName] = [];
169
-
170
-
171
- existingMap[elementName].push({
172
- element, name: elementName, source: $location, parent: getBaseName(parent), error_parent,
173
- });
174
- }
140
+ return elements;
141
+ }
175
142
 
176
- return existingMap;
177
- }
143
+ /**
144
+ * Merge two maps of elements together
145
+ *
146
+ * @param {object} mapA Map a - will be returned
147
+ * @param {object} mapB Map b - will not be returned
148
+ * @returns {object} mapA
149
+ */
150
+ function mergeElementMaps(mapA, mapB) {
151
+ for (const elementName in mapB) {
152
+ if (!mapA[elementName])
153
+ mapA[elementName] = [];
154
+
155
+ mapB[elementName].forEach(e => mapA[elementName].push(e));
178
156
  }
179
157
 
180
- /**
181
- * Return the name part of the artifact name - no namespace etc.
182
- * @param {string|object} name Absolute name of the artifact
183
- */
184
- function getBaseName(name) {
185
- if (!name)
186
- return name;
158
+ return mapA;
159
+ }
187
160
 
188
- if (name.id)
189
- return name.id.substring( name.id.lastIndexOf('.')+1 );
161
+ /**
162
+ * Merge elements into an existing map
163
+ *
164
+ * @param {any} existingMap map to merge into - will be returned
165
+ * @param {object} elements elements to merge into the map
166
+ * @param {CSN.Location} $location $location of the elements - where they come from
167
+ * @param {any} [parent] Name of the parent of the elements, alias before ref
168
+ * @param {any} [error_parent] Parent name to use for error messages, ref before alias
169
+ * @returns {object} existingMap
170
+ */
171
+ function mergeElementsIntoMap(existingMap, elements, $location, parent, error_parent) {
172
+ for (const elementName in elements) {
173
+ const element = elements[elementName];
174
+ if (!existingMap[elementName])
175
+ existingMap[elementName] = [];
190
176
 
191
- return name.substring( name.lastIndexOf('.')+1 )
177
+
178
+ existingMap[elementName].push({
179
+ element, name: elementName, source: $location, parent: getBaseName(parent), error_parent,
180
+ });
192
181
  }
182
+
183
+ return existingMap;
184
+ }
185
+
186
+ /**
187
+ * Return the name part of the artifact name - no namespace etc.
188
+ * @param {string|object} name Absolute name of the artifact
189
+ */
190
+ function getBaseName(name) {
191
+ if (!name)
192
+ return name;
193
+
194
+ if (name.id)
195
+ return name.id.substring( name.id.lastIndexOf('.')+1 );
196
+
197
+ return name.substring( name.lastIndexOf('.')+1 )
193
198
  }
194
199
 
195
200
  /**
@@ -216,11 +221,11 @@ function getUtils(model) {
216
221
 
217
222
  /**
218
223
  * Create an object to track visited objects identified by a unique string.
219
- * @param {string} [id] Initial entry (optional)
224
+ * @param {string} [initialId] Initial entry (optional)
220
225
  */
221
- function createVisited(id) {
226
+ function createVisited(initialId) {
222
227
  let visited = Object.create(null);
223
- check(id);
228
+ check(initialId);
224
229
  return { check };
225
230
 
226
231
  /**
@@ -231,7 +236,7 @@ function getUtils(model) {
231
236
  function check(id) {
232
237
  if (!id) return;
233
238
  if (visited[id]) {
234
- throw new Error('Circular dependency');
239
+ throw new ModelError('Circular dependency');
235
240
  }
236
241
  visited[id] = true;
237
242
  }
@@ -245,7 +250,7 @@ function getUtils(model) {
245
250
  if (model.definitions[defName])
246
251
  return model.definitions[defName]
247
252
  else
248
- throw new Error(`Nonexistent definition in the model: '${defName}'`);
253
+ throw new ModelError(`Nonexistent definition in the model: '${defName}'`);
249
254
  }
250
255
 
251
256
  /**
@@ -298,7 +303,7 @@ function getUtils(model) {
298
303
 
299
304
  // Return true if 'node' is a managed association element
300
305
  // TODO: what about elements having a type, which (finally) is an assoc?
301
- function isManagedAssociationElement(node) {
306
+ function isManagedAssociation(node) {
302
307
  return node.target !== undefined && node.on === undefined && node.keys;
303
308
  }
304
309
 
@@ -536,7 +541,7 @@ function getUtils(model) {
536
541
  if (cycleCheck) {
537
542
  let visited = path.length? type + ':' + path.join('.') : type;
538
543
  if (cycleCheck[visited])
539
- throw new Error('Circular type chain on type ' + type);
544
+ throw new ModelError('Circular type chain on type ' + type);
540
545
  else
541
546
  cycleCheck[visited] = true;
542
547
  }
@@ -649,7 +654,7 @@ function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterate
649
654
  }
650
655
 
651
656
  path = [...path]; // Copy
652
- const propsWithMembers = (iterateOptions.elementsOnly ? ['elements'] : ['elements', 'enum', 'foreignKeys', 'actions', 'params']);
657
+ const propsWithMembers = (iterateOptions.elementsOnly ? ['elements'] : ['elements', 'enum', 'actions', 'params']);
653
658
  propsWithMembers.forEach((prop) => forEachGeneric( construct, prop, callback, path, iterateOptions ));
654
659
  }
655
660
 
@@ -706,45 +711,6 @@ function forEachGeneric( obj, prop, callback, path = [], iterateOptions = {}) {
706
711
  }
707
712
  }
708
713
 
709
- /**
710
- * For each property named 'ref' in 'node' (recursively), call callback(ref, node, path)
711
- *
712
- * @param {object} node
713
- * @param {refCallback|refCallback[]} callback
714
- * @param {CSN.Path} path
715
- */
716
- function forEachRef(node, callback, path = []) {
717
- if (node === null || typeof node !== 'object') {
718
- // Primitive node
719
- return;
720
- }
721
-
722
- if(node._ignore){
723
- return;
724
- }
725
-
726
- if(Array.isArray(node)){
727
- for (let i = 0; i < node.length; i++) {
728
- // Descend recursively
729
- forEachRef(node[i], callback, path.concat([i]));
730
- }
731
- } else {
732
- for (let name in node) {
733
- if (!Object.hasOwnProperty.call( node, name ))
734
- continue;
735
- // If ref found within a non-dictionary, call callback
736
- if (name === 'ref' && Object.getPrototypeOf(node)) {
737
- if(Array.isArray(callback))
738
- callback.forEach(cb => cb( node.ref, node, path ));
739
- else
740
- callback( node.ref, node, path );
741
- }
742
- // Descend recursively
743
- forEachRef(node[name], callback, path.concat([name]));
744
- }
745
- }
746
- }
747
-
748
714
  // Like Object.assign() but copies also non enumerable properties
749
715
  function assignAll(target, ...sources) {
750
716
  sources.forEach(source => {
@@ -830,39 +796,6 @@ function forAllQueries(query, callback, path = []){
830
796
  }
831
797
  }
832
798
 
833
- function forAllElements(artifact, artifactName, cb, includeActions = false){
834
- if(artifact.elements) {
835
- cb(artifact, artifact.elements, ['definitions', artifactName, 'elements']);
836
- }
837
-
838
- if(includeActions && artifact.actions) {
839
- Object.entries(artifact.actions).forEach( ([actionName, action]) => {
840
- const path = ['definitions', artifactName, 'actions', actionName];
841
- if(action.params) {
842
- Object.entries(action.params).forEach( ([paramName, param]) => {
843
- if(param.elements)
844
- cb(param, param.elements, path.concat(['params', paramName, 'elements']));
845
- });
846
- }
847
- if(action.returns && action.returns.elements)
848
- cb(action.returns, action.returns.elements,path.concat(['returns', 'elements']));
849
- });
850
- }
851
-
852
- if(artifact.query) {
853
- forAllQueries(artifact.query, (q, p) => {
854
- const s = q.SELECT;
855
- if(s) {
856
- if(s.elements) {
857
- cb(s, s.elements, [...p, 'elements']);
858
- } else if(s.$elements) { // huh?, is just refloc output
859
- cb(s, s.$elements, [...p, '$elements']);
860
- }
861
- }
862
- }, ['definitions', artifactName, 'query'])
863
- }
864
- }
865
-
866
799
  /**
867
800
  * Compare a given annotation value with an expectation value and return
868
801
  *
@@ -925,48 +858,48 @@ function isEdmPropertyRendered(elementCsn, options) {
925
858
 
926
859
  /**
927
860
  * Return the resulting database name for (absolute) 'artifactName', depending on the current naming
928
- * convention.
861
+ * mode.
929
862
  *
930
- * - For the 'hdbcds' naming convention, this means converting '.' to '::' on
863
+ * - For the 'hdbcds' naming mode, this means converting '.' to '::' on
931
864
  * the border between namespace and top-level artifact and correctly replacing some '.' with '_'.
932
- * - For the 'plain' naming convention, it means converting all '.' to '_' and uppercasing.
933
- * - For the 'quoted' naming convention, this means correctly replacing some '.' with '_'.
865
+ * - For the 'plain' naming mode, it means converting all '.' to '_' and upper-casing.
866
+ * - For the 'quoted' naming mode, this means correctly replacing some '.' with '_'.
934
867
  *
935
868
  * If the old function signature is used - with a namespace as the third argument - the result might be wrong,
936
869
  * since the '.' -> '_' conversion for quoted/hdbcds is missing.
937
870
  *
938
- * @param {string} artifactName The name of the artifact
939
- * @param {('plain'|'quoted'|'hdbcds')} namingConvention The naming convention to use
871
+ * @param {string} artifactName The fully qualified name of the artifact
872
+ * @param {('plain'|'quoted'|'hdbcds')} sqlMapping The naming mode to use
940
873
  * @param {CSN.Model|string|undefined} csn
941
- * @returns {string} The resulting database name for (absolute) 'artifactName', depending on the current naming convention.
874
+ * @returns {string} The resulting database name for (absolute) 'artifactName', depending on the current naming mode.
942
875
  */
943
- function getArtifactDatabaseNameOf(artifactName, namingConvention, csn) {
876
+ function getArtifactDatabaseNameOf(artifactName, sqlMapping, csn) {
944
877
  if(csn && typeof csn === 'object' && csn.definitions)
945
- if (namingConvention === 'quoted' || namingConvention === 'hdbcds') {
946
- return getResultingName(csn, namingConvention, artifactName);
878
+ if (sqlMapping === 'quoted' || sqlMapping === 'hdbcds') {
879
+ return getResultingName(csn, sqlMapping, artifactName);
947
880
  }
948
- else if (namingConvention === 'plain') {
881
+ else if (sqlMapping === 'plain') {
949
882
  return artifactName.replace(/\./g, '_').toUpperCase();
950
883
  } else {
951
- throw new Error('Unknown naming convention: ' + namingConvention);
884
+ throw new Error('Unknown naming mode: ' + sqlMapping);
952
885
  }
953
886
  else {
954
887
  console.error(`This invocation of "getArtifactCdsPersistenceName" is deprecated, as it doesn't produce correct output with definition names containing dots - please provide a CSN as the third parameter.`);
955
- if (namingConvention === 'hdbcds') {
888
+ if (sqlMapping === 'hdbcds') {
956
889
  if (csn) {
957
890
  const namespace = String(csn);
958
891
  return `${namespace}::${artifactName.substring(namespace.length + 1)}`;
959
892
  }
960
893
  return artifactName;
961
894
  }
962
- else if (namingConvention === 'plain') {
895
+ else if (sqlMapping === 'plain') {
963
896
  return artifactName.replace(/\./g, '_').toUpperCase();
964
897
  }
965
- else if (namingConvention === 'quoted') {
898
+ else if (sqlMapping === 'quoted') {
966
899
  return artifactName;
967
900
  }
968
901
  else {
969
- throw new Error('Unknown naming convention: ' + namingConvention);
902
+ throw new Error('Unknown naming mode: ' + sqlMapping);
970
903
  }
971
904
  }
972
905
  }
@@ -1052,29 +985,29 @@ function getUnderscoredName(startIndex, parts, csn) {
1052
985
 
1053
986
 
1054
987
  /**
1055
- * Return the resulting database element name for 'elemName', depending on the current naming
1056
- * convention.
1057
- * - For the 'hdbcds' naming convention, this is just 'elemName'.
1058
- * - For the 'plain' naming convention, it means converting all '.' to '_' and uppercasing.
1059
- * - For the 'quoted' naming convention, it means converting all '.' to '_'.
1060
- * No other naming conventions are accepted
988
+ * Return the resulting database element name for 'elemName', depending on the current
989
+ * naming mode.
990
+ * - For the 'hdbcds' naming mode, this is just 'elemName'.
991
+ * - For the 'plain' naming mode, it means converting all '.' to '_' and upper-casing.
992
+ * - For the 'quoted' naming mode, it means converting all '.' to '_'.
993
+ * No other naming modes are accepted!
1061
994
  *
1062
- * @param {string} elemName Name of the element
1063
- * @param {('plain'|'quoted'|'hdbcds')} namingConvention The naming convention to use
1064
- * @returns {string} The resulting database element name for 'elemName', depending on the current naming convention.
995
+ * @param {string} elemName The name of the element
996
+ * @param {('plain'|'quoted'|'hdbcds')} sqlMapping The naming mode to use
997
+ * @returns {string} The resulting database element name for 'elemName', depending on the current naming mode.
1065
998
  */
1066
- function getElementDatabaseNameOf(elemName, namingConvention) {
1067
- if (namingConvention === 'hdbcds') {
999
+ function getElementDatabaseNameOf(elemName, sqlMapping) {
1000
+ if (sqlMapping === 'hdbcds') {
1068
1001
  return elemName;
1069
1002
  }
1070
- else if (namingConvention === 'plain') {
1003
+ else if (sqlMapping === 'plain') {
1071
1004
  return elemName.replace(/\./g, '_').toUpperCase();
1072
1005
  }
1073
- else if (namingConvention === 'quoted') {
1006
+ else if (sqlMapping === 'quoted') {
1074
1007
  return elemName.replace(/\./g, '_');
1075
1008
  }
1076
1009
  else {
1077
- throw new Error('Unknown naming convention: ' + namingConvention);
1010
+ throw new Error('Unknown naming mode: ' + sqlMapping);
1078
1011
  }
1079
1012
  }
1080
1013
 
@@ -1152,7 +1085,7 @@ function setDependencies( csn ) {
1152
1085
  * @returns {boolean}
1153
1086
  */
1154
1087
  function isPersistedOnDatabase(art) {
1155
- return !([ 'entity', 'view' ].includes(art.kind) && (art.abstract || hasAnnotationValue(art, '@cds.persistence.skip')));
1088
+ return !('entity' === art.kind && (art.abstract || hasAnnotationValue(art, '@cds.persistence.skip')));
1156
1089
  }
1157
1090
 
1158
1091
  /**
@@ -1220,10 +1153,10 @@ function mergeOptions(...optionsObjects) {
1220
1153
  }
1221
1154
  // Check against improper overwriting
1222
1155
  if (isObject(left) && !Array.isArray(left) && (Array.isArray(right) || isScalar(right))) {
1223
- throw new Error(`Cannot overwrite structured option "${name}" with array or scalar value`);
1156
+ throw new ModelError(`Cannot overwrite structured option "${name}" with array or scalar value`);
1224
1157
  }
1225
1158
  if ((isScalar(left) && typeof left !== 'boolean' || Array.isArray(left)) && isObject(right) && !Array.isArray(right)) {
1226
- throw new Error(`Cannot overwrite non-boolean scalar or array option "${name}" with structured value`);
1159
+ throw new ModelError(`Cannot overwrite non-boolean scalar or array option "${name}" with structured value`);
1227
1160
  }
1228
1161
 
1229
1162
  // Copy or overwrite properties from right to left
@@ -1378,7 +1311,7 @@ function forEachPath(node, callback) {
1378
1311
  * @returns {boolean}
1379
1312
  */
1380
1313
  function hasValidSkipOrExists(artifact) {
1381
- return (artifact.kind === 'entity' || artifact.kind === 'view') &&
1314
+ return artifact.kind === 'entity' &&
1382
1315
  (hasAnnotationValue(artifact, '@cds.persistence.exists', true) || hasAnnotationValue(artifact, '@cds.persistence.skip', true))
1383
1316
 
1384
1317
  }
@@ -1447,7 +1380,7 @@ function getServiceNames(csn) {
1447
1380
  }
1448
1381
 
1449
1382
  /**
1450
- * Check wether the artifact is @cds.persistence.skip
1383
+ * Check whether the artifact is @cds.persistence.skip
1451
1384
  *
1452
1385
  * @param {CSN.Artifact} artifact
1453
1386
  * @returns {Boolean}
@@ -1501,6 +1434,42 @@ function getVariableReplacement(ref, options) {
1501
1434
  }
1502
1435
  }
1503
1436
 
1437
+ /**
1438
+ *
1439
+ * @param {object} obj
1440
+ * @param {*} other
1441
+ * @param {boolean} noExtendedProps
1442
+ * @returns {boolean} returns equality
1443
+ *
1444
+ * noExtendedProps remove '$', '_' and '@' properties from
1445
+ * the comparision. This eliminates false negatives such as
1446
+ * mismatching $locations or @odata.foreignKey4.
1447
+ */
1448
+ function isDeepEqual(obj, other, noExtendedProps) {
1449
+ let objectKeys = Object.keys(obj);
1450
+ let otherKeys = Object.keys(other);
1451
+
1452
+ if(noExtendedProps) {
1453
+ objectKeys = objectKeys.filter(k => !['@', '$', '_'].includes(k[0]));
1454
+ otherKeys = otherKeys.filter(k => !['@', '$', '_'].includes(k[0]));
1455
+ }
1456
+ if (objectKeys.length !== otherKeys.length)
1457
+ return false;
1458
+
1459
+ for (let key of objectKeys) {
1460
+ const areValuesObjects = (obj[key] != null && typeof obj[key] === 'object')
1461
+ && (other[key] !== null && typeof other[key] === 'object');
1462
+
1463
+ if (areValuesObjects) {
1464
+ if (!isDeepEqual(obj[key], other[key], noExtendedProps))
1465
+ return false;
1466
+ } else if (obj[key] !== other[key]) {
1467
+ return false;
1468
+ }
1469
+ }
1470
+ return true;
1471
+ }
1472
+
1504
1473
  module.exports = {
1505
1474
  getUtils,
1506
1475
  cloneCsn,
@@ -1511,9 +1480,7 @@ module.exports = {
1511
1480
  forEachDefinition,
1512
1481
  forEachMember,
1513
1482
  forEachMemberRecursively,
1514
- forEachRef,
1515
1483
  forAllQueries,
1516
- forAllElements,
1517
1484
  hasAnnotationValue,
1518
1485
  isEdmPropertyRendered,
1519
1486
  getArtifactDatabaseNameOf,
@@ -1541,5 +1508,7 @@ module.exports = {
1541
1508
  getServiceNames,
1542
1509
  isSkipped,
1543
1510
  walkCsnPath,
1544
- getVariableReplacement
1511
+ getVariableReplacement,
1512
+ implicitAs,
1513
+ isDeepEqual,
1545
1514
  };