@sap/cds-compiler 4.0.0 → 4.1.2

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 (85) hide show
  1. package/CHANGELOG.md +115 -5
  2. package/bin/cdsc.js +12 -12
  3. package/doc/CHANGELOG_BETA.md +11 -0
  4. package/lib/api/main.js +60 -12
  5. package/lib/api/validate.js +1 -1
  6. package/lib/base/location.js +6 -7
  7. package/lib/base/message-registry.js +84 -38
  8. package/lib/base/messages.js +11 -10
  9. package/lib/base/model.js +6 -2
  10. package/lib/checks/defaultValues.js +6 -6
  11. package/lib/checks/foreignKeys.js +0 -5
  12. package/lib/checks/onConditions.js +17 -12
  13. package/lib/checks/queryNoDbArtifacts.js +132 -72
  14. package/lib/checks/sql-snippets.js +15 -4
  15. package/lib/checks/types.js +3 -3
  16. package/lib/checks/utils.js +1 -1
  17. package/lib/compiler/assert-consistency.js +44 -16
  18. package/lib/compiler/base.js +1 -0
  19. package/lib/compiler/builtins.js +7 -8
  20. package/lib/compiler/checks.js +274 -197
  21. package/lib/compiler/classes.js +62 -0
  22. package/lib/compiler/cycle-detector.js +3 -3
  23. package/lib/compiler/define.js +63 -50
  24. package/lib/compiler/extend.js +38 -20
  25. package/lib/compiler/finalize-parse-cdl.js +2 -1
  26. package/lib/compiler/generate.js +0 -8
  27. package/lib/compiler/index.js +9 -7
  28. package/lib/compiler/kick-start.js +2 -0
  29. package/lib/compiler/populate.js +139 -110
  30. package/lib/compiler/propagator.js +4 -3
  31. package/lib/compiler/resolve.js +157 -126
  32. package/lib/compiler/shared.js +706 -404
  33. package/lib/compiler/tweak-assocs.js +21 -10
  34. package/lib/compiler/utils.js +228 -36
  35. package/lib/edm/annotations/genericTranslation.js +30 -2
  36. package/lib/edm/edm.js +4 -1
  37. package/lib/edm/edmPreprocessor.js +12 -5
  38. package/lib/edm/edmUtils.js +2 -4
  39. package/lib/gen/Dictionary.json +34 -10
  40. package/lib/gen/language.checksum +1 -1
  41. package/lib/gen/language.interp +1 -1
  42. package/lib/gen/languageParser.js +3987 -3963
  43. package/lib/json/from-csn.js +43 -47
  44. package/lib/json/to-csn.js +11 -11
  45. package/lib/language/antlrParser.js +2 -1
  46. package/lib/language/genericAntlrParser.js +52 -43
  47. package/lib/language/language.g4 +59 -59
  48. package/lib/language/multiLineStringParser.js +2 -0
  49. package/lib/main.d.ts +5 -0
  50. package/lib/model/csnRefs.js +37 -19
  51. package/lib/model/csnUtils.js +20 -16
  52. package/lib/model/revealInternalProperties.js +29 -21
  53. package/lib/model/sortViews.js +4 -2
  54. package/lib/modelCompare/compare.js +112 -39
  55. package/lib/modelCompare/utils/filter.js +54 -24
  56. package/lib/optionProcessor.js +6 -6
  57. package/lib/render/manageConstraints.js +20 -17
  58. package/lib/render/toCdl.js +34 -20
  59. package/lib/render/toHdbcds.js +2 -2
  60. package/lib/render/toRename.js +4 -9
  61. package/lib/render/toSql.js +77 -26
  62. package/lib/render/utils/common.js +3 -3
  63. package/lib/render/utils/unique.js +52 -0
  64. package/lib/transform/db/applyTransformations.js +61 -20
  65. package/lib/transform/db/assertUnique.js +7 -8
  66. package/lib/transform/db/associations.js +2 -2
  67. package/lib/transform/db/cdsPersistence.js +8 -8
  68. package/lib/transform/db/expansion.js +17 -21
  69. package/lib/transform/db/flattening.js +23 -23
  70. package/lib/transform/db/rewriteCalculatedElements.js +20 -14
  71. package/lib/transform/db/temporal.js +1 -1
  72. package/lib/transform/db/transformExists.js +8 -7
  73. package/lib/transform/db/views.js +73 -33
  74. package/lib/transform/draft/db.js +11 -9
  75. package/lib/transform/draft/odata.js +1 -1
  76. package/lib/transform/{forOdataNew.js → forOdata.js} +56 -42
  77. package/lib/transform/forRelationalDB.js +69 -75
  78. package/lib/transform/localized.js +6 -5
  79. package/lib/transform/odata/toFinalBaseType.js +3 -3
  80. package/lib/transform/{transformUtilsNew.js → transformUtils.js} +4 -101
  81. package/lib/transform/translateAssocsToJoins.js +14 -28
  82. package/package.json +1 -1
  83. package/share/messages/check-proper-type-of.md +1 -1
  84. package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
  85. package/share/messages/message-explanations.json +1 -1
@@ -7,7 +7,7 @@ const { cloneCsnNonDict,
7
7
  isAspect, walkCsnPath, isPersistedOnDatabase,
8
8
  } = require('../model/csnUtils');
9
9
  const { makeMessageFunction } = require('../base/messages');
10
- const transformUtils = require('./transformUtilsNew');
10
+ const transformUtils = require('./transformUtils');
11
11
  const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
12
12
  const { csnRefs, pathId, traverseQuery } = require('../model/csnRefs');
13
13
  const { checkCSNVersion } = require('../json/csnVersion');
@@ -26,7 +26,7 @@ const expansion = require('./db/expansion');
26
26
  const assertUnique = require('./db/assertUnique');
27
27
  const generateDrafts = require('./draft/db');
28
28
  const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
29
- const { getViewTransformer } = require('./db/views');
29
+ const { getViewTransformer, ensureColumnNames } = require('./db/views');
30
30
  const cdsPersistence = require('./db/cdsPersistence');
31
31
  const temporal = require('./db/temporal');
32
32
  const associations = require('./db/associations')
@@ -98,17 +98,17 @@ function forEachDefinition(csn, cb) {
98
98
  * - (250) Remove name space definitions again (only in forRelationalDB). Maybe we can omit inserting namespace definitions
99
99
  * completely (TODO)
100
100
  *
101
- * @param {CSN.Model} inputModel
101
+ * @param {CSN.Model} csn
102
102
  * @param {CSN.Options} options
103
103
  * @param {string} moduleName The calling compiler module name, e.g. `to.hdi` or `to.hdbcds`.
104
104
  */
105
- function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
105
+ function transformForRelationalDBWithCsn(csn, 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
 
109
109
  timetrace.start('Clone CSN');
110
110
  /** @type {CSN.Model} */
111
- let csn = cloneCsnNonDict(inputModel, options);
111
+ csn = cloneCsnNonDict(csn, options);
112
112
  timetrace.stop('Clone CSN');
113
113
 
114
114
  checkCSNVersion(csn, options);
@@ -117,20 +117,13 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
117
117
  // There is also an explicit default length via options.defaultStringLength
118
118
  const implicitDefaultLengths = getDefaultTypeLengths(options.sqlDialect);
119
119
 
120
+ /** @type {object} */
120
121
  let csnUtils;
122
+ /** @type {object} */
123
+ let messageFunctions;
121
124
  let message, error, warning, info; // message functions
122
125
  /** @type {() => void} */
123
126
  let throwWithAnyError;
124
- // csnUtils
125
- let artifactRef,
126
- inspectRef,
127
- effectiveType,
128
- initDefinition,
129
- dropDefinitionCache,
130
- get$combined,
131
- getCsnDef,
132
- isAssocOrComposition,
133
- addStringAnnotationTo;
134
127
  // transformUtils
135
128
  let addDefaultTypeFacets,
136
129
  expandStructsInExpression,
@@ -148,6 +141,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
148
141
  bindCsnReference();
149
142
  }
150
143
 
144
+ ensureColumnNames(csn, options, csnUtils);
145
+
151
146
  const dialect = options.sqlDialect;
152
147
  const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
153
148
  if (!doA2J)
@@ -159,14 +154,14 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
159
154
  timetrace.start('Validate');
160
155
  // Run validations on CSN - each validator function has access to the message functions and the inspect ref via this
161
156
  const cleanup = validate.forRelationalDB(csn, {
162
- message, error, warning, info, inspectRef, effectiveType, artifactRef, csnUtils, csn, options, isAspect
157
+ ...messageFunctions, csnUtils, ...csnUtils, csn, options, isAspect
163
158
  });
164
159
  timetrace.stop('Validate');
165
160
 
166
- rewriteCalculatedElementsInViews(csn, options, pathDelimiter, error);
161
+ rewriteCalculatedElementsInViews(csn, options, csnUtils, pathDelimiter, messageFunctions);
167
162
 
168
163
  // Needs to happen before tuple expansion, so the newly generated WHERE-conditions have it applied
169
- handleExists(csn, options, error, inspectRef, initDefinition, dropDefinitionCache);
164
+ handleExists(csn, options, error, csnUtils.inspectRef, csnUtils.initDefinition, csnUtils.dropDefinitionCache);
170
165
 
171
166
  // Check if structured elements and managed associations are compared in an expression
172
167
  // and expand these structured elements. This tuple expansion allows all other
@@ -179,19 +174,17 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
179
174
 
180
175
  throwWithAnyError();
181
176
 
182
- const transformCsn = transformUtils.transformModel;
183
-
184
177
  forEachDefinition(csn, [
185
178
  // (001) Add a temporal where condition to views where applicable before assoc2join
186
179
  // assoc2join eventually rewrites the table aliases
187
- temporal.getViewDecorator(csn, {info}, csnUtils),
180
+ temporal.getViewDecorator(csn, messageFunctions, csnUtils),
188
181
  // check unique constraints - further processing is done in rewriteUniqueConstraints
189
182
  assertUnique.prepare(csn, options, error, info)
190
183
  ]);
191
184
 
192
185
  if(doA2J) {
193
186
  // Expand a structured thing in: keys, columns, order by, group by
194
- expansion.expandStructureReferences(csn, options, pathDelimiter, {error, info, throwWithAnyError}, csnUtils);
187
+ expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils);
195
188
  bindCsnReference();
196
189
  }
197
190
 
@@ -217,7 +210,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
217
210
  flattening.flattenElements(csn, options, pathDelimiter, error);
218
211
  } else {
219
212
  // For to.hdbcds with naming mode hdbcds we also need to resolve the types
220
- flattening.resolveTypeReferences(csn, options, undefined, pathDelimiter);
213
+ flattening.resolveTypeReferences(csn, options, new WeakMap(), pathDelimiter);
221
214
  }
222
215
 
223
216
  // (010) If requested, translate associations to joins
@@ -227,7 +220,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
227
220
  bindCsnReference();
228
221
 
229
222
  const redoProjections = [];
230
- // Use the "raw" forEachDefinition here to ensure that the _ignore takes effect
223
+ // Use the "raw" forEachDefinition here to ensure that the $ignore takes effect
231
224
  _forEachDefinition(csn, (artifact) => {
232
225
  if(artifact.kind === 'entity' && artifact.projection) {
233
226
  artifact.query = { SELECT: artifact.projection };
@@ -242,8 +235,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
242
235
  }
243
236
  })
244
237
  } else if(artifact.kind === 'annotation' || artifact.kind === 'action' || artifact.kind === 'function' || artifact.kind === 'event'){
245
- // _ignore actions etc. - this loop seemed handy for this, as we can hook into an existing if
246
- artifact._ignore = true;
238
+ // $ignore actions etc. - this loop seemed handy for this, as we can hook into an existing if
239
+ artifact.$ignore = true;
247
240
  }
248
241
  });
249
242
 
@@ -251,20 +244,30 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
251
244
 
252
245
  timetrace.start('Transform CSN')
253
246
 
254
- // (000) Rename primitive types, make UUID a String
255
- transformCsn(csn, {
256
- type: (val, node, key) => {
257
- renamePrimitiveTypesAndUuid(val, node, key);
258
- addDefaultTypeFacets(node, implicitDefaultLengths);
259
- },
247
+ // Rename primitive types, make UUID a String; replace `items` by cds.LargeString
248
+ //
249
+ // First, gather all nodes that are arrayed: Don't replace inline, or getFinalTypeInfo()
250
+ // may not return `.items` for types that were already processed.
251
+ {
252
+ const removeItems = new Set();
253
+ applyTransformations(csn, {
254
+ type: (node) => {
255
+ if (node.items || node.type && csnUtils.getFinalTypeInfo(node.type)?.items)
256
+ removeItems.add(node);
257
+ renamePrimitiveTypesAndUuid(node.type, node, 'type');
258
+ addDefaultTypeFacets(node, implicitDefaultLengths);
259
+ },
260
+ items: (node) => removeItems.add(node),
261
+ });
260
262
  // no support for array-of - turn into CLOB/Text
261
263
  // must be done after A2J or compiler checks could change
262
264
  // (e.g. annotation def checks for arrayed types)
263
- items: (val, node) => {
265
+ for (const node of removeItems) {
264
266
  node.type = 'cds.LargeString';
265
267
  delete node.items;
266
- },
267
- }, true);
268
+ }
269
+ removeItems.clear();
270
+ }
268
271
 
269
272
  forEachDefinition(csn, [
270
273
  // (040) Ignore entities and views that are abstract or implemented
@@ -273,7 +276,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
273
276
  cdsPersistence.getAnnoProcessor(),
274
277
  // (050) Check @cds.valid.from/to only on entity
275
278
  // Views are checked in (001), unbalanced valid.from/to's or mismatching origins
276
- temporal.getAnnotationHandler(csn, options, pathDelimiter, {error})
279
+ temporal.getAnnotationHandler(csn, options, pathDelimiter, messageFunctions)
277
280
  ]);
278
281
 
279
282
  // eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
@@ -285,7 +288,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
285
288
 
286
289
  // (045) Strip all query-ish properties from views and projections annotated with '@cds.persistence.table',
287
290
  // and make them entities
288
- forEachDefinition(csn, cdsPersistence.getPersistenceTableProcessor(csn, options, {error}));
291
+ forEachDefinition(csn, cdsPersistence.getPersistenceTableProcessor(csn, options, messageFunctions));
289
292
 
290
293
  // Allow using managed associations as steps in on-conditions to access their fks
291
294
  // To be done after handleAssociations, since then the foreign keys of the managed assocs
@@ -341,19 +344,19 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
341
344
  createReferentialConstraints(csn, options);
342
345
 
343
346
  // no constraints for drafts
344
- generateDrafts(csn, options, pathDelimiter, { info, warning, error });
347
+ generateDrafts(csn, options, pathDelimiter, messageFunctions);
345
348
 
346
349
  // Set the final constraint paths and produce hana tc indexes if required
347
350
  // See function comment for extensive information.
348
351
  assertUnique.rewrite(csn, options, pathDelimiter);
349
352
 
350
353
  // Associations that point to things marked with @cds.persistence.skip are removed
351
- forEachDefinition(csn, cdsPersistence.getAssocToSkippedIgnorer(csn, options, {info}, csnUtils));
354
+ forEachDefinition(csn, cdsPersistence.getAssocToSkippedIgnorer(csn, options, messageFunctions, csnUtils));
352
355
 
353
356
  // Apply view-specific transformations
354
357
  // (160) Projections now finally become views
355
358
  // Replace managed association in group/order by with foreign keys
356
- const transformEntityOrViewPass2 = getViewTransformer(csn, options, {error, info}, transformCommon);
359
+ const transformEntityOrViewPass2 = getViewTransformer(csn, options, messageFunctions, transformCommon);
357
360
  forEachDefinition(csn, transformViews);
358
361
 
359
362
  // Recursively apply transformCommon and attach @cds.persistence.name
@@ -384,14 +387,14 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
384
387
 
385
388
  const killers = {
386
389
  // Used to ignore actions etc from processing and remove associations/elements
387
- '_ignore': function (parent, a, b, path){
390
+ '$ignore': function (parent, a, b, path){
388
391
  if(path.length > 2) {
389
392
  const tail = path[path.length-1];
390
393
  const parentPath = path.slice(0, -1)
391
394
  const parentParent = walkCsnPath(csn, parentPath);
392
395
  delete parentParent[tail];
393
396
  } else {
394
- delete parent._ignore;
397
+ delete parent.$ignore;
395
398
  }
396
399
  },
397
400
  // Still used in flattenStructuredElements - in db/flattening.js
@@ -441,7 +444,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
441
444
  /* ----------------------------------- Functions start here -----------------------------------------------*/
442
445
 
443
446
  function bindCsnReference(){
444
- ({ error, warning, info, message, throwWithAnyError } = makeMessageFunction(csn, options, moduleName));
447
+ messageFunctions = makeMessageFunction(csn, options, moduleName);
448
+ ({ error, warning, info, message, throwWithAnyError } = messageFunctions);
445
449
 
446
450
  ({ flattenStructuredElement,
447
451
  flattenStructStepsInRef,
@@ -451,22 +455,12 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
451
455
  expandStructsInExpression,
452
456
  csnUtils
453
457
  } = transformUtils.getTransformers(csn, options, pathDelimiter));
454
-
455
- ({ artifactRef,
456
- inspectRef,
457
- effectiveType,
458
- initDefinition,
459
- dropDefinitionCache,
460
- get$combined,
461
- getCsnDef,
462
- isAssocOrComposition,
463
- addStringAnnotationTo,
464
- } = csnUtils);
465
458
  }
466
459
 
467
460
  function bindCsnReferenceOnly(){
468
461
  // invalidate caches for CSN ref API
469
- ({ artifactRef, inspectRef, effectiveType, initDefinition, dropDefinitionCache } = csnRefs(csn));
462
+ const csnRefApi = csnRefs(csn);
463
+ Object.assign(csnUtils, csnRefApi);
470
464
  }
471
465
 
472
466
  function handleMixinOnConditions(artifact, artifactName) {
@@ -513,7 +507,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
513
507
  // not explicitly in column list, check query sources
514
508
  // get$combined also includes elements which are part of "excluding {}"
515
509
  // this shouldn't be an issue here, as such references get rejected
516
- const elementsOfQuerySources = get$combined(query);
510
+ const elementsOfQuerySources = csnUtils.get$combined(query);
517
511
  forEach(elementsOfQuerySources, (id, element) => {
518
512
  // if the ref points to an element which is not explicitly exposed in the column list,
519
513
  // but through the '*' operator -> replace the $projection / $self with the correct source entity
@@ -538,7 +532,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
538
532
  * @param {string} artifactName
539
533
  */
540
534
  function transformViews(artifact, artifactName) {
541
- if (!artifact._ignore) {
535
+ if (!artifact.$ignore) {
542
536
  // Do things specific for entities and views (pass 2)
543
537
  if ((artifact.kind === 'entity') && artifact.query) {
544
538
 
@@ -557,7 +551,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
557
551
 
558
552
  const process = (parent, prop, query, path) => {
559
553
  transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop))
560
- replaceAssociationsInGroupByOrderBy(parent, options, inspectRef, error, path.concat(prop));
554
+ replaceAssociationsInGroupByOrderBy(parent, options, csnUtils.inspectRef, error, path.concat(prop));
561
555
  return query;
562
556
  }
563
557
  applyTransformationsOnNonDictionary(csn.definitions, artifactName, {
@@ -572,9 +566,9 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
572
566
  * @param {string} artifactName
573
567
  */
574
568
  function recursivelyApplyCommon(artifact, artifactName) {
575
- if (!artifact._ignore) {
569
+ if (!artifact.$ignore) {
576
570
  if (artifact.kind !== 'service' && artifact.kind !== 'context')
577
- addStringAnnotationTo('@cds.persistence.name', getArtifactDatabaseNameOf(artifactName, options.sqlMapping, csn, options.sqlDialect), artifact);
571
+ csnUtils.addStringAnnotationTo('@cds.persistence.name', getArtifactDatabaseNameOf(artifactName, options.sqlMapping, csn, options.sqlDialect), artifact);
578
572
 
579
573
  forEachMemberRecursively(artifact, (member, memberName, property, path) => {
580
574
  if (property === 'returns')
@@ -584,7 +578,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
584
578
  // Virtual elements in entities and types are not annotated, as they have no DB representation.
585
579
  // In views they are, as we generate a null expression for them (null as <colname>)
586
580
  if ((!member.virtual || artifact.query))
587
- addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(memberName, options.sqlMapping, options.sqlDialect), member);
581
+ csnUtils.addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(memberName, options.sqlMapping, options.sqlDialect), member);
588
582
  }, [ 'definitions', artifactName ]);
589
583
  }
590
584
  }
@@ -594,7 +588,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
594
588
  * @param {string} artifactName
595
589
  */
596
590
  function removeKeyPropInType(artifact, artifactName) {
597
- if (!artifact._ignore && artifact.kind === 'type') {
591
+ if (!artifact.$ignore && artifact.kind === 'type') {
598
592
  forEachMemberRecursively(artifact, (member) => {
599
593
  if (member.key)
600
594
  delete member.key;
@@ -618,7 +612,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
618
612
  function doit(dict, subPath) {
619
613
  for (const elemName in dict) {
620
614
  const elem = dict[elemName];
621
- if (elem.on && isAssocOrComposition(elem))
615
+ if (elem.on && csnUtils.isAssocOrComposition(elem))
622
616
  processBacklinkAssoc(elem, elemName, artifact, artifactName, subPath.concat([ elemName, 'on' ]));
623
617
  }
624
618
  }
@@ -641,7 +635,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
641
635
  // For HANA: Report an error on
642
636
  // - view with parameters that has an element of type association/composition
643
637
  // - association that points to entity with parameters
644
- if (options.sqlDialect === 'hana' && member.target && isAssocOrComposition(member) && !isBetaEnabled(options, 'assocsWithParams')) {
638
+ if (options.sqlDialect === 'hana' && member.target && csnUtils.isAssocOrComposition(member) && !isBetaEnabled(options, 'assocsWithParams')) {
645
639
  if (artifact.params) {
646
640
  // HANA does not allow 'WITH ASSOCIATIONS' on something with parameters:
647
641
  // SAP DBTech JDBC: [7]: feature not supported: parameterized sql view cannot support association: line 1 col 1 (at pos 0)
@@ -676,7 +670,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
676
670
  * @param {string} artifactName
677
671
  */
678
672
  function handleChecksForWithParameters(artifact, artifactName) {
679
- if (!artifact._ignore && artifact.params && (artifact.kind === 'entity')) {
673
+ if (!artifact.$ignore && artifact.params && (artifact.kind === 'entity')) {
680
674
  if (!artifact.query) { // table entity with params
681
675
  // Allow with plain
682
676
  error(null, [ 'definitions', artifactName ], { '#': options.toSql ? 'sql' : 'std' }, {
@@ -714,7 +708,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
714
708
  // restore all (non-enumerable) properties that wouldn't survive reaugmentation/compactification into the new compact model
715
709
  forEachDefinition(csn, (art, artName) => {
716
710
  if(art['$tableConstraints']) {
717
- setProp(newCsn.definitions[artName], '$tableConstraints', art['$tableConstraints']);
711
+ newCsn.definitions[artName].$tableConstraints = art['$tableConstraints'];
718
712
  }
719
713
  if (art.technicalConfig)
720
714
  newCsn.definitions[artName].technicalConfig = art.technicalConfig;
@@ -790,7 +784,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
790
784
  if (elem.default && elem.default['#']) {
791
785
  let Enum = elem.enum;
792
786
  if (!Enum && !isBuiltinType(elem.type)) {
793
- const typeDef = getCsnDef(elem.type);
787
+ const typeDef = csnUtils.getCsnDef(elem.type);
794
788
  Enum = typeDef && typeDef.enum;
795
789
  }
796
790
  if (!Enum) {
@@ -852,7 +846,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
852
846
  // Check if one side is $self and the other an association
853
847
  // (if so, replace all three tokens with the condition generated from the other side, in parentheses)
854
848
  if (isDollarSelfOrProjectionOperand(xprArgs[i]) && isAssociationOperand(xprArgs[i + 2], path.concat([ i + 2 ]))) {
855
- const assoc = inspectRef(path.concat([ i + 2 ])).art;
849
+ const assoc = csnUtils.inspectRef(path.concat([ i + 2 ])).art;
856
850
  if (multipleExprs)
857
851
  result.push('(');
858
852
  const backlinkName = xprArgs[i + 2].ref[xprArgs[i + 2].ref.length - 1];
@@ -867,7 +861,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
867
861
  attachBacklinkInformation(backlinkName);
868
862
  }
869
863
  else if (isDollarSelfOrProjectionOperand(xprArgs[i + 2]) && isAssociationOperand(xprArgs[i], path.concat([ i ]))) {
870
- const assoc = inspectRef(path.concat([ i ])).art;
864
+ const assoc = csnUtils.inspectRef(path.concat([ i ])).art;
871
865
  if (multipleExprs)
872
866
  result.push('(');
873
867
  const backlinkName = xprArgs[i].ref[xprArgs[i].ref.length - 1];
@@ -943,7 +937,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
943
937
  if(assoc.keys.length)
944
938
  return transformDollarSelfComparisonWithManagedAssoc(assocOp, assoc, assocName, elemName);
945
939
  else {
946
- elem._ignore = true;
940
+ elem.$ignore = true;
947
941
  return [];
948
942
  }
949
943
  }
@@ -1034,10 +1028,10 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
1034
1028
  function checkTypeParameters(artifact, artifactName) {
1035
1029
  forEachMemberRecursively(artifact, (member, memberName, prop, path) => {
1036
1030
  // Check type parameters (length, precision, scale ...)
1037
- if (!member._ignore && member.type)
1031
+ if (!member.$ignore && member.type)
1038
1032
  _check(member, memberName, csn, path);
1039
1033
 
1040
- if (!member._ignore && member.items && member.items.type)
1034
+ if (!member.$ignore && member.items && member.items.type)
1041
1035
  _check(member.items, memberName, csn, path.concat([ 'items' ]));
1042
1036
  }, [ 'definitions', artifactName ]);
1043
1037
 
@@ -1079,7 +1073,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
1079
1073
  // (which can currently only be 'positiveInteger') and (optional) the value is in a given range
1080
1074
  function checkTypeParamValue(node, paramName, range = null, path = null) {
1081
1075
  const paramValue = node[paramName];
1082
- if (paramValue === undefined || paramValue === null) {
1076
+ if (paramValue == null) {
1083
1077
  if(options.toSql || artifact.query || !['cds.Binary','cds.hana.BINARY', 'cds.hana.NCHAR','cds.hana.CHAR'].includes(node.type)) {
1084
1078
  return true;
1085
1079
  } else {
@@ -1134,7 +1128,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
1134
1128
  if (typeof val === 'object' && val.ref) {
1135
1129
  // Replace a reference by references to it's elements, if it is structured
1136
1130
  const path = [ 'definitions', artName, 'technicalConfig', dialect, 'indexes', name, idx ];
1137
- const { art } = inspectRef(path);
1131
+ const { art } = csnUtils.inspectRef(path);
1138
1132
  if (!art) {
1139
1133
  // A reference that has no artifact (e.g. the reference to the index name itself). Just copy it over
1140
1134
  flattenedIndex.push(val);
@@ -1176,8 +1170,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
1176
1170
  }
1177
1171
  }
1178
1172
  }
1179
- }
1180
1173
 
1174
+ }
1181
1175
 
1182
1176
  module.exports = {
1183
1177
  transformForRelationalDBWithCsn,
@@ -330,8 +330,8 @@ function _addLocalizationViews(csn, options, useJoins, config) {
330
330
  let keyCount = 0;
331
331
  let textElements = [];
332
332
 
333
- forEachGeneric(art, 'elements', (elem, elemName /*, prop, path*/) => {
334
- if (elem._ignore) // from HANA backend
333
+ forEachGeneric(art, 'elements', (elem, elemName , _prop, path) => {
334
+ if (elem.$ignore) // from SAP HANA backend
335
335
  return;
336
336
 
337
337
  if (elem.key || elem.$key)
@@ -340,9 +340,10 @@ function _addLocalizationViews(csn, options, useJoins, config) {
340
340
  if (elem.key || elem.$key || elem.localized)
341
341
  textElements.push( elemName );
342
342
 
343
- // TODO: Already warned about in extend.js
344
- // if (elem.key && isLocalized)
345
- // warning( 'localized-key', path, {}, 'Keyword "localized" is ignored for primary keys' );
343
+ if ((elem.key|| elem.$key) && elem.localized) {
344
+ messageFunctions.warning('def-ignoring-localized', path, { keyword: 'localized' },
345
+ 'Keyword $(KEYWORD) is ignored for primary keys');
346
+ }
346
347
  }, artPath);
347
348
 
348
349
  if (textElements.length <= keyCount || keyCount <= 0)
@@ -94,7 +94,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
94
94
  function expandToFinalBaseType(node, defName) {
95
95
  if (!node) return;
96
96
  // TODO: Clarify how should events be handled?
97
- // They are not treated by the transformUtilsNew::toFinalBaseType function
97
+ // They are not treated by the transformUtils::toFinalBaseType function
98
98
  // in the same manner as named types, because the elements of structured events are not
99
99
  // propagated as it is with types.
100
100
  // It is ok to skip the expansion to the final base type for now as events are not rendered in
@@ -130,7 +130,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
130
130
  */
131
131
  if (isBuiltinType(finalBaseType.type)) {
132
132
  /*
133
- use transformUtilsNew::toFinalBaseType for the moment,
133
+ use transformUtils::toFinalBaseType for the moment,
134
134
  as it is collects along the chain of types
135
135
  attributes that need to be propagated
136
136
  enum, length, scale, etc.
@@ -161,7 +161,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
161
161
  */
162
162
  if (isBuiltinType(finalBaseType.type)) {
163
163
  /*
164
- use transformUtilsNew::toFinalBaseType for the moment,
164
+ use transformUtils::toFinalBaseType for the moment,
165
165
  as it is collects along the chain of types
166
166
  attributes that need to be propagated
167
167
  enum, length, scale, etc.
@@ -420,17 +420,10 @@ function getTransformers(model, options, pathDelimiter = '_') {
420
420
  if (typeof type === 'string' && isBuiltinType(type))
421
421
  return;
422
422
 
423
- let typeRef = null;
424
- if (resolved.has(type)) {
425
- typeRef = resolved.get(type)?.art
426
- // The cached entry may not be resolved, yet.
427
- if (typeRef.type && !isBuiltinType(typeRef.type))
428
- typeRef = getFinalTypeInfo(typeRef.type);
429
- } else {
430
- typeRef = getFinalTypeInfo(type);
431
- }
423
+ const typeRef = getFinalTypeInfo(type, (t) => resolved.get(t)?.art || csnUtils.artifactRef(t));
432
424
  if(!typeRef)
433
425
  return;
426
+
434
427
  if (typeRef.elements || typeRef.items) {
435
428
  // Copy elements/items and we're finished. No need to look up actual base type,
436
429
  // since it must also be structured and must contain at least as many elements,
@@ -909,7 +902,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
909
902
  if (annotation === undefined) {
910
903
  throw new CompilerAssertion('Annotation ' + fromName + ' not found in ' + JSON.stringify(node));
911
904
  }
912
- if(node[toName] === undefined || node[toName] === null) {
905
+ if(node[toName] == null) {
913
906
  delete node[fromName];
914
907
  node[toName] = annotation;
915
908
  }
@@ -931,9 +924,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
931
924
  if (value === undefined) {
932
925
  throw new CompilerAssertion('Annotation value must not be undefined');
933
926
  }
934
-
935
- if(node[name] === undefined || node[name] === null)
936
- node[name] = value;
927
+ node[name] ??= value;
937
928
  }
938
929
 
939
930
  /**
@@ -1352,93 +1343,6 @@ function getTransformers(model, options, pathDelimiter = '_') {
1352
1343
 
1353
1344
  }
1354
1345
 
1355
- /**
1356
- * Modify the given CSN/artifact in-place, applying the given customTransformations.
1357
- * Dictionaries are correctly handled - a "type" transformer will not be called on an entity called "type".
1358
- *
1359
- * A custom transformation function has the following signature:
1360
- * (any, object, string, CSN.Path) => undefined
1361
- *
1362
- * Given that we have a custom transformation for "type" and stumble upon a thing like below:
1363
- *
1364
- * {
1365
- * type: "cds.String",
1366
- * anotherProp: 1
1367
- * }
1368
- *
1369
- * The input for the function would be:
1370
- *
1371
- * ("cds.String", { type: <>, anotherProp: <>}, "type", [xy, "type"])
1372
- *
1373
- * @param {CSN.Model} csn
1374
- * @param {object} customTransformations Dictionary of functions to apply - if the property matches a key in this dict, it will be called
1375
- * @param {boolean} [transformNonEnumerableElements=false] Transform non-enumerable elements to work with cds linked...
1376
- * @returns {CSN.Model|CSN.Artifact} Return the CSN/artifact
1377
- */
1378
- function transformModel(csn, customTransformations, transformNonEnumerableElements=false){
1379
- const transformers = {
1380
- elements: dictionary,
1381
- definitions: dictionary,
1382
- actions: dictionary,
1383
- params: dictionary,
1384
- enum: dictionary,
1385
- mixin: dictionary,
1386
- args: dictionary
1387
- };
1388
-
1389
- const csnPath = [];
1390
- if (csn.definitions)
1391
- dictionary( csn, 'definitions', csn.definitions );
1392
- else {
1393
- // fake it till you make it
1394
- const obj = { definitions: Object.create(null)};
1395
- obj.definitions.thing = csn;
1396
- dictionary(obj, 'definitions', obj.definitions);
1397
- }
1398
-
1399
- return csn;
1400
-
1401
- function standard( parent, prop, node ) {
1402
- // checking for .kind and .type is safe because annotations with such properties, are already flattened out
1403
- const isAnnotation = () => (typeof prop === 'string' && prop.startsWith('@') && !node.kind && !node.type);
1404
- if (!node || node._ignore || typeof node !== 'object' || !{}.propertyIsEnumerable.call( parent, prop ) || isAnnotation())
1405
- return;
1406
-
1407
- csnPath.push( prop );
1408
-
1409
- if (Array.isArray(node)) {
1410
- node.forEach( (n, i) => standard( node, i, n ) );
1411
- }
1412
- else {
1413
- const iterateOver = Object.getOwnPropertyNames( node );
1414
- // cds-linked resolves types and add's them to elements as non-enum - need to be processed
1415
- if(transformNonEnumerableElements && node.elements && !Object.prototype.propertyIsEnumerable.call(node, 'elements')){
1416
- iterateOver.push('elements');
1417
- }
1418
- for (const name of iterateOver) {
1419
- if(customTransformations[name])
1420
- customTransformations[name](node[name], node, name, csnPath.concat(name))
1421
-
1422
- const trans = transformers[name] || standard;
1423
- trans( node, name, node[name] );
1424
- }
1425
- }
1426
- csnPath.pop();
1427
- }
1428
- function dictionary( node, prop, dict ) {
1429
- csnPath.push( prop );
1430
-
1431
- if (Array.isArray(dict)) {
1432
- dict.forEach( (n, i) => standard(dict, i, n))
1433
- } else {
1434
- for (const name of Object.getOwnPropertyNames( dict ))
1435
- standard( dict, name, dict[name] );
1436
- }
1437
-
1438
- csnPath.pop();
1439
- }
1440
- }
1441
-
1442
1346
  /**
1443
1347
  * Mandatory input transformation for all backends:
1444
1348
  * Replace
@@ -1465,7 +1369,6 @@ function rewriteBuiltinTypeRef(csn) {
1465
1369
  module.exports = {
1466
1370
  // This function retrieves the actual exports
1467
1371
  getTransformers,
1468
- transformModel,
1469
1372
  RelationalOperators,
1470
1373
  rewriteBuiltinTypeRef,
1471
1374
  };