@sap/cds-compiler 6.9.2 → 7.0.1

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 (69) hide show
  1. package/CHANGELOG.md +86 -2
  2. package/bin/cdsc.js +4 -33
  3. package/doc/IncompatibleChanges_v7.md +639 -0
  4. package/lib/api/main.js +4 -56
  5. package/lib/api/options.js +6 -15
  6. package/lib/api/validate.js +1 -0
  7. package/lib/base/builtins.js +1 -2
  8. package/lib/base/csnRefs.js +2 -6
  9. package/lib/base/message-registry.js +82 -76
  10. package/lib/base/messages.js +23 -4
  11. package/lib/base/optionProcessor.js +2 -72
  12. package/lib/base/specialOptions.js +20 -17
  13. package/lib/checks/defaultValues.js +1 -39
  14. package/lib/checks/hasPersistedElements.js +19 -3
  15. package/lib/checks/parameters.js +0 -34
  16. package/lib/checks/selectItems.js +2 -38
  17. package/lib/checks/typeParameters.js +162 -0
  18. package/lib/checks/validator.js +5 -8
  19. package/lib/compiler/assert-consistency.js +19 -5
  20. package/lib/compiler/checks.js +47 -43
  21. package/lib/compiler/define.js +6 -6
  22. package/lib/compiler/extend.js +102 -111
  23. package/lib/compiler/generate.js +4 -8
  24. package/lib/compiler/populate.js +4 -7
  25. package/lib/compiler/propagator.js +9 -9
  26. package/lib/compiler/resolve.js +205 -7
  27. package/lib/compiler/shared.js +76 -82
  28. package/lib/compiler/tweak-assocs.js +102 -22
  29. package/lib/compiler/utils.js +57 -12
  30. package/lib/compiler/xpr-rewrite.js +2 -15
  31. package/lib/edm/annotations/edmJson.js +14 -10
  32. package/lib/edm/annotations/genericTranslation.js +3 -1
  33. package/lib/edm/annotations/preprocessAnnotations.js +9 -26
  34. package/lib/edm/csn2edm.js +27 -20
  35. package/lib/edm/edmUtils.js +25 -0
  36. package/lib/gen/CdlGrammar.checksum +1 -1
  37. package/lib/gen/CdlParser.js +2237 -2241
  38. package/lib/gen/Dictionary.json +17 -2
  39. package/lib/json/from-csn.js +67 -52
  40. package/lib/json/to-csn.js +28 -25
  41. package/lib/language/textUtils.js +0 -13
  42. package/lib/main.d.ts +34 -59
  43. package/lib/main.js +1 -1
  44. package/lib/model/csnUtils.js +9 -8
  45. package/lib/parsers/AstBuildingParser.js +45 -55
  46. package/lib/parsers/Lexer.js +2 -0
  47. package/lib/parsers/identifiers.js +0 -9
  48. package/lib/render/toCdl.js +41 -40
  49. package/lib/render/toSql.js +8 -1
  50. package/lib/render/utils/common.js +1 -1
  51. package/lib/render/utils/sql.js +2 -3
  52. package/lib/tool-lib/enrichCsn.js +1 -2
  53. package/lib/transform/db/applyTransformations.js +7 -5
  54. package/lib/transform/db/assertUnique.js +8 -51
  55. package/lib/transform/db/associations.js +1 -1
  56. package/lib/transform/db/cdsPersistence.js +1 -15
  57. package/lib/transform/db/expansion.js +9 -12
  58. package/lib/transform/db/flattening.js +1 -1
  59. package/lib/transform/db/groupByOrderBy.js +0 -16
  60. package/lib/transform/db/views.js +57 -161
  61. package/lib/transform/draft/db.js +2 -2
  62. package/lib/transform/forOdata.js +25 -14
  63. package/lib/transform/forRelationalDB.js +93 -301
  64. package/lib/transform/localized.js +33 -102
  65. package/lib/transform/odata/flattening.js +11 -2
  66. package/lib/transform/transformUtils.js +25 -3
  67. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -2
  68. package/package.json +2 -2
  69. package/lib/render/toHdbcds.js +0 -1810
@@ -3,20 +3,19 @@
3
3
  const { isBetaEnabled } = require('../base/specialOptions');
4
4
  const shuffleGen = require('../utils/shuffle');
5
5
  const {
6
- forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
6
+ applyTransformationsOnNonDictionary,
7
7
  getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
8
- walkCsnPath, isPersistedOnDatabase,
8
+ walkCsnPath,
9
9
  } = require('../model/csnUtils');
10
10
  const transformUtils = require('./transformUtils');
11
11
  const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
12
12
  const {
13
- csnRefs, pathId, traverseQuery, columnAlias,
13
+ csnRefs, traverseQuery,
14
14
  } = require('../base/csnRefs');
15
15
  const { checkCSNVersion } = require('../json/csnVersion');
16
16
  const validate = require('../checks/validator');
17
- const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../checks/selectItems');
18
17
  const { addTenantFields } = require('../transform/addTenantFields');
19
- const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
18
+ const { addLocalizationViewsWithJoins } = require('../transform/localized');
20
19
  const { timetrace } = require('../utils/timetrace');
21
20
  const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
22
21
  const { setProp, forEach } = require('../utils/objectUtils');
@@ -36,7 +35,7 @@ const associations = require('./db/associations');
36
35
  const backlinks = require('./db/backlinks');
37
36
  const { getDefaultTypeLengths } = require('../render/utils/common');
38
37
  const { featureFlags, removeFeatureFlags } = require('./featureFlags');
39
- const { cloneCsnNonDict, cloneFullCsn } = require('../base/cloneCsn');
38
+ const { cloneFullCsn } = require('../base/cloneCsn');
40
39
  const { processSqlServices, createServiceDummy } = require('./db/processSqlServices');
41
40
  const { expandWildcard } = require('./db/expansion');
42
41
  const removeEnums = require('../checks/enums');
@@ -105,14 +104,17 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
105
104
  const setQueryFeatureFlags = getQueryFeatureFlagSetter(csn);
106
105
  const setDefinitionFeatureFlags = getDefinitionFeatureFlagSetter(csn, options);
107
106
 
108
- // csnRefs cache init, expandWildcards, ensureColumnNames, and feature flags in one loop
107
+ // csnRefs cache init and feature flags in one loop
109
108
  // as preparation for the following transformations and validations
110
109
  forEachDefinition(csn, (def) => {
111
110
  csnUtils.initDefinition(def);
112
111
  if (def.query || def.projection) {
113
112
  traverseQuery(def.query || def, null, null, (query) => {
114
- expandWildcard(query, csnUtils, options);
115
- ensureColumnNames(query, csnUtils, options);
113
+ // Normalize implicit wildcards (no columns → ['*']) so downstream code
114
+ // can always rely on an explicit columns array being present.
115
+ const SELECT = query.SELECT ?? query.projection;
116
+ if (SELECT)
117
+ SELECT.columns ??= [ '*' ];
116
118
  setQueryFeatureFlags(query);
117
119
  });
118
120
  }
@@ -120,9 +122,22 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
120
122
  });
121
123
 
122
124
  const dialect = options.sqlDialect;
123
- const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
124
- if (!doA2J)
125
- forEachDefinition(csn, handleMixinOnConditions);
125
+
126
+ const hasCalcElements = csn.meta?.[featureFlags]?.$calculatedElements;
127
+
128
+ // Only expand wildcards early for views whose inferred elements contain calculated
129
+ // elements (have $calc). All other views defer expansion past validation to keep
130
+ // column lists compact during the expensive enrichment + validation passes.
131
+ if (hasCalcElements) {
132
+ forEachDefinition(csn, (def) => {
133
+ if ((def.query || def.projection) && defHasCalculatedElements(def)) {
134
+ traverseQuery(def.query || def, null, null, (query) => {
135
+ expandWildcard(query, csnUtils, options);
136
+ ensureColumnNames(query, csnUtils, options);
137
+ });
138
+ }
139
+ });
140
+ }
126
141
 
127
142
  // replace all type refs to builtin types with direct type
128
143
  transformUtils.rewriteBuiltinTypeRef(csn);
@@ -137,7 +152,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
137
152
  // exit if validators found errors
138
153
  throwWithAnyError();
139
154
 
140
- if (csn.meta?.[featureFlags]?.$calculatedElements)
155
+ if (hasCalcElements)
141
156
  rewriteCalculatedElementsInViews(csn, options, csnUtils, pathDelimiter, messageFunctions);
142
157
 
143
158
  timetrace.start('Where-Exists handling');
@@ -163,12 +178,21 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
163
178
  assertUnique.prepare(csn, options, messageFunctions),
164
179
  ]);
165
180
 
166
- if (doA2J) {
167
- // Expand a structured thing in: keys, columns, order by, group by
168
- // In addition, kill all non-sql-backend relevant annotations
169
- expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils, { processAnnotations: true });
170
- bindCsnReference();
171
- }
181
+ // Deferred wildcard expansion for any remaining unexpanded queries.
182
+ // expandWildcard() returns early when no '*' exists, so already-expanded views are a no-op.
183
+ forEachDefinition(csn, (def) => {
184
+ if (def.query || def.projection) {
185
+ traverseQuery(def.query || def, null, null, (query) => {
186
+ expandWildcard(query, csnUtils, options);
187
+ ensureColumnNames(query, csnUtils, options);
188
+ });
189
+ }
190
+ });
191
+
192
+ // Expand a structured thing in: keys, columns, order by, group by
193
+ // In addition, kill all non-sql-backend relevant annotations
194
+ expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils, { processAnnotations: true });
195
+ bindCsnReference();
172
196
 
173
197
  timetrace.stop('Expand Structures (expressions + refs)');
174
198
 
@@ -196,7 +220,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
196
220
  // With that, we could still ensure the processing order (assuming we don't run into problems with scoping).
197
221
  // To analyze: Increased memory vs. saved cycles
198
222
  // Looked at it with AFC: This is only a small part of the overall processing time, enrich step of validator is just as expensive
199
- if (doA2J) {
223
+ {
200
224
  const resolved = new WeakMap();
201
225
  // No refs with struct-steps exist anymore
202
226
  flattening.flattenAllStructStepsInRefs(csn, options, messageFunctions, resolved, pathDelimiter);
@@ -206,17 +230,12 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
206
230
  // No structured elements exists anymore
207
231
  flattening.flattenElements(csn, options, messageFunctions, pathDelimiter);
208
232
  }
209
- else {
210
- // For to.hdbcds with naming mode hdbcds we also need to resolve the types
211
- flattening.resolveTypeReferences(csn, options, messageFunctions, new WeakMap(), pathDelimiter);
212
- }
213
233
  timetrace.stop('Flattening (refs + elements)');
214
234
 
215
235
  // With flattening errors, it makes little sense to continue.
216
236
  throwWithAnyError();
217
237
 
218
- if (doA2J)
219
- handleAssocToJoins();
238
+ handleAssocToJoins();
220
239
 
221
240
  if (options.testMode && csn.definitions)
222
241
  csn.definitions = shuffleDict(csn.definitions);
@@ -269,25 +288,22 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
269
288
  temporal.getAnnotationHandler(csn, options, pathDelimiter, messageFunctions),
270
289
  ]);
271
290
 
272
- if (doA2J) {
273
- // eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
274
- flattening.handleManagedAssociationsAndCreateForeignKeys(
275
- csn, options, messageFunctions, pathDelimiter, true, csnUtils,
276
- { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') }
277
- );
278
- forEachDefinition(csn, flattenIndexes);
279
- // Managed associations get an on-condition - in views and entities
280
- associations.attachOnConditions(csn, csnUtils, pathDelimiter);
281
-
282
- // Add the foreign keys also to the columns if the association itself was explicitly selected
283
- // TODO: Extend the expansion to also expand managed to their foreign
284
- // TODO: Remember where in .elements we had associations and do it then?
285
- applyTransformations(csn, {
286
- columns: expandManagedToFksInArray(),
287
- groupBy: expandManagedToFksInArray(true),
288
- orderBy: expandManagedToFksInArray(true),
289
- }, [], { allowArtifact: artifact => artifact.query !== undefined || artifact.projection !== undefined });
290
- }
291
+ flattening.handleManagedAssociationsAndCreateForeignKeys(
292
+ csn, options, messageFunctions, pathDelimiter, true, csnUtils,
293
+ { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') }
294
+ );
295
+ forEachDefinition(csn, flattenIndexes);
296
+ // Managed associations get an on-condition - in views and entities
297
+ associations.attachOnConditions(csn, csnUtils, pathDelimiter);
298
+
299
+ // Add the foreign keys also to the columns if the association itself was explicitly selected
300
+ // TODO: Extend the expansion to also expand managed to their foreign
301
+ // TODO: Remember where in .elements we had associations and do it then?
302
+ applyTransformations(csn, {
303
+ columns: expandManagedToFksInArray(),
304
+ groupBy: expandManagedToFksInArray(true),
305
+ orderBy: expandManagedToFksInArray(true),
306
+ }, [], { allowArtifact: artifact => artifact.query !== undefined || artifact.projection !== undefined });
291
307
 
292
308
  {
293
309
  // Strip all query-ish properties from views and projections annotated with '@cds.persistence.table',
@@ -296,8 +312,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
296
312
  // Allow using managed associations as steps in on-conditions to access their fks
297
313
  // To be done after handleAssociations, since then the foreign keys of the managed assocs
298
314
  // are part of the elements
299
- if (doA2J)
300
- fns.push(associations.getFKAccessFinalizer(csn, options, csnUtils, pathDelimiter, true));
315
+ fns.push(associations.getFKAccessFinalizer(csn, options, csnUtils, pathDelimiter, true));
301
316
 
302
317
  forEachDefinition(csn, fns);
303
318
  }
@@ -307,33 +322,19 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
307
322
  // handled and before handleDBChecks which removes the localized attribute.
308
323
  // Association elements of localized convenience views do not have hidden properties
309
324
  // like $managed set, so we cannot do this earlier on.
310
- if (doA2J)
311
- addLocalizationViewsWithJoins(csn, options);
312
- else
313
- addLocalizationViews(csn, options);
325
+ addLocalizationViewsWithJoins(csn, options);
314
326
 
315
327
  forEachDefinition(csn, [
316
- (definition, artName, prop, path) => {
317
- if (!doA2J && definition.query && isPersistedOnDatabase(definition)) {
318
- // reject managed association and structure publishing for to-hdbcds.hdbcds
319
- const that = { csnUtils, options, error };
320
- rejectManagedAssociationsAndStructuresForHdbcdsNames.call(that, definition, path);
321
- }
322
- },
323
328
  // Transform '$self' in backlink associations to appropriate key comparisons
324
329
  // Must happen before draft processing because the artificial ON-conditions in generated
325
330
  // draft shadow entities have crooked '_artifact' links, confusing the backlink processing.
326
331
  // But it must also happen after flattenForeignKeys has been called for all artifacts,
327
332
  // because otherwise we would produce wrong ON-conditions for the keys involved. Sigh ...
328
- backlinks.getBacklinkTransformer(csnUtils, messageFunctions, options, pathDelimiter, doA2J),
333
+ backlinks.getBacklinkTransformer(csnUtils, messageFunctions, options, pathDelimiter, true),
329
334
  ]);
330
335
 
331
- /**
332
- * Referential Constraints are only supported for sql-dialect "hana" and "sqlite".
333
- * For to.hdbcds with naming mode "hdbcds", no foreign keys are calculated,
334
- * hence we do not generate the referential constraints for them.
335
- */
336
- if (options.sqlDialect !== 'plain' && options.sqlDialect !== 'h2' && doA2J)
336
+ // Referential Constraints are only supported for sql-dialect "hana" and "sqlite".
337
+ if (options.sqlDialect !== 'plain' && options.sqlDialect !== 'h2')
337
338
  createReferentialConstraints(csn, options);
338
339
 
339
340
  // no constraints for drafts
@@ -364,31 +365,8 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
364
365
  generateFioriTreeViews(artifact, artifactName, messageFunctions, csnUtils, { setAnnotation, addElement, createScalarElement }, options);
365
366
  }, transformViews ]);
366
367
 
367
- if (!doA2J) {
368
- forEachDefinition(csn, [
369
- // Strip 'key' property from type elements
370
- removeKeyPropInType,
371
- (artifact, artifactName) => {
372
- if (artifact.kind === 'type') {
373
- forEachMemberRecursively(artifact, (member, memberName, prop, path) => {
374
- // Check type parameters (length, precision, scale ...)
375
- if (!member.$ignore) {
376
- if (member.type)
377
- checkTypeParameters(member, artifact, path);
378
- if (member.items?.type)
379
- checkTypeParameters(member.items, artifact, path.concat([ 'items' ]));
380
- }
381
- }, [ 'definitions', artifactName ]);
382
- }
383
- },
384
- ]);
385
- }
386
-
387
368
  // TODO: Could we maybe merge this with the final applyTransformations?
388
369
  applyTransformations(csn, {
389
- type: (parent, prop, type, path) => {
390
- checkTypeParameters(parent, csn.definitions[path[1]], path);
391
- },
392
370
  $tableConstraints: (parent, prop, tableConstraints, path) => {
393
371
  /* assert that there will be no conflicting unique- and foreign key constraint identifiers */
394
372
  assertConstraintIdentifierUniqueness(parent, path[1], path, error);
@@ -400,9 +378,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
400
378
  if ((!element.virtual || artifact.query))
401
379
  csnUtils.addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(name, options.sqlMapping, options.sqlDialect), element);
402
380
  });
403
- // Remove leading $self to keep renderer-diffs smaller
404
- if (doA2J && options.transformation === 'hdbcds')
405
- flattening.removeLeadingSelf(parent, prop, elements);
406
381
  },
407
382
  }, [ (definitions, artifactName, artifact) => {
408
383
  // Attach @cds.persistence.name to artifacts
@@ -456,7 +431,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
456
431
  }
457
432
  },
458
433
  includes: killProp,
459
- masked: killProp,
460
434
  localized: killProp,
461
435
  };
462
436
 
@@ -467,25 +441,24 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
467
441
  };
468
442
  }
469
443
 
470
- if (options.sqlDialect === 'hana' && options.withHanaAssociations === false && doA2J)
444
+ if (options.sqlDialect === 'hana' && options.withHanaAssociations === false)
471
445
  killers.target = killParent;
472
446
 
473
447
 
474
448
  const killTypes = [];
475
449
 
476
- if (doA2J) { // replace types and aspects with dummies to shrink overall CSN size
477
- killers.kind = (parent, prop, kind, path) => {
478
- if (kind === 'type' || kind === 'aspect') {
479
- const artifactName = path[1];
480
- killTypes.push(() => {
481
- csn.definitions[artifactName] = {
482
- kind,
483
- type: 'cds.Integer',
484
- };
485
- });
486
- }
487
- };
488
- }
450
+ // replace types and aspects with dummies to shrink overall CSN size
451
+ killers.kind = (parent, prop, kind, path) => {
452
+ if (kind === 'type' || kind === 'aspect') {
453
+ const artifactName = path[1];
454
+ killTypes.push(() => {
455
+ csn.definitions[artifactName] = {
456
+ kind,
457
+ type: 'cds.Integer',
458
+ };
459
+ });
460
+ }
461
+ };
489
462
 
490
463
  applyTransformations(csn, killers, [], { skipIgnore: false });
491
464
 
@@ -524,66 +497,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
524
497
  Object.assign(csnUtils, csnRefApi);
525
498
  }
526
499
 
527
- // For non-A2J only
528
- function handleMixinOnConditions(artifact, artifactName) {
529
- if (!artifact.query) // projections can't have mixins
530
- return;
531
- forAllQueries(artifact.query, (query, path) => {
532
- const { mixin } = query.SELECT || {};
533
- if (mixin) {
534
- query.SELECT.columns
535
- // filter for associations which are used in the SELECT
536
- .filter(c => c.ref && c.ref.length > 1)
537
- .forEach((usedAssoc) => {
538
- const assocName = pathId(usedAssoc.ref[0]);
539
- const mixinAssociation = mixin[assocName];
540
- if (mixinAssociation)
541
- mixinAssociation.on = getResolvedMixinOnCondition(mixinAssociation, query, assocName, path.concat([ 'mixin', assocName ]));
542
- });
543
- }
544
- }, [ 'definitions', artifactName, 'query' ]);
545
- }
546
-
547
- // For non-A2J only
548
- function getResolvedMixinOnCondition(mixinAssociation, query, assocName, path) {
549
- const referencedThroughStar = query.SELECT.columns.some(column => column === '*');
550
- return mixinAssociation.on.map(handeMixinOnConditionPart);
551
-
552
- function handeMixinOnConditionPart(onConditionPart, i) {
553
- let columnToReplace;
554
- if (onConditionPart.ref && (onConditionPart.ref[0] === '$projection' || onConditionPart.ref[0] === '$self')) {
555
- const { links } = csnUtils.inspectRef(path.concat([ 'on', i ]));
556
- if (links)
557
- columnToReplace = onConditionPart.ref[links.length - 1];
558
- }
559
- if (!columnToReplace)
560
- return onConditionPart;
561
-
562
- const replaceWith = query.SELECT.columns.find(col => columnAlias(col) === columnToReplace);
563
- if (!replaceWith && referencedThroughStar) {
564
- // not explicitly in column list, check query sources
565
- // get$combined also includes elements which are part of "excluding {}"
566
- // this shouldn't be an issue here, as such references get rejected
567
- const elementsOfQuerySources = csnUtils.get$combined(query);
568
- forEach(elementsOfQuerySources, (id, element) => {
569
- // if the ref points to an element which is not explicitly exposed in the column list,
570
- // but through the '*' operator -> replace the $projection / $self with the correct source entity
571
- if (id === columnToReplace)
572
- onConditionPart.ref[0] = element[0].parent;
573
- });
574
- return onConditionPart;
575
- }
576
- else if (replaceWith) {
577
- const clone = cloneCsnNonDict(replaceWith, options);
578
- delete clone.cast; // No implicit CAST in on-condition
579
- delete clone.as;
580
- return clone;
581
- }
582
-
583
- return onConditionPart;
584
- }
585
- }
586
-
587
500
 
588
501
  /**
589
502
  * @param {CSN.Artifact} artifact
@@ -593,21 +506,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
593
506
  if (!artifact.$ignore) {
594
507
  // Do things specific for entities and views (pass 2)
595
508
  if ((artifact.kind === 'entity') && artifact.query) {
596
- // First pass: Set alias name for SELECTs without table alias. Required for setting proper table aliases
597
- // for HDBCDS in naming mode HDBCDS. We use the same schema as the core-compiler, so duplicates should
598
- // have already been reported.
599
- if (options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds') {
600
- let selectDepth = 0;
601
- traverseQuery(artifact.query, null, null, (query, fromSelect) => {
602
- if (!query.ref && !query.as && fromSelect) {
603
- // Use +1; for UNION, it's the next select, for SELECT, it's increased later.
604
- query.as = `$_select_${ selectDepth + 1 }__`;
605
- }
606
- if (query.SELECT)
607
- ++selectDepth;
608
- });
609
- }
610
-
611
509
  const process = (parent, prop, query, path) => {
612
510
  transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop));
613
511
  replaceAssociationsInGroupByOrderBy(parent, options, csnUtils.inspectRef, error, path.concat(prop));
@@ -620,19 +518,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
620
518
  }
621
519
  }
622
520
 
623
- /**
624
- * @param {CSN.Artifact} artifact
625
- * @param {string} artifactName
626
- */
627
- function removeKeyPropInType(artifact, artifactName) {
628
- if (!doA2J && !artifact.$ignore && artifact.kind === 'type') {
629
- forEachMemberRecursively(artifact, (member) => {
630
- if (member.key)
631
- delete member.key;
632
- }, [ 'definitions', artifactName ]);
633
- }
634
- }
635
-
636
521
  function handleAssocToJoins() {
637
522
  timetrace.start('A2J');
638
523
  // the augmentor isn't able to deal with technical configurations and since assoc2join can ignore it we
@@ -688,116 +573,9 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
688
573
  // Length/Precision/Scale is done in addDefaultTypeFacets
689
574
  }
690
575
 
691
- /**
692
- * Check that required actual parameters on 'node.type' are set, that their values are in the correct range etc.
693
-
694
- * @param {*} node
695
- * @param {CSN.Artifact} artifact
696
- * @param {CSN.Path} path
697
- */
698
- function checkTypeParameters(node, artifact, path) {
699
- if (node.type && !node.virtual) {
700
- const absolute = node.type;
701
- switch (absolute) {
702
- case 'cds.String':
703
- case 'cds.Binary':
704
- case 'cds.hana.VARCHAR': {
705
- checkTypeParamValue(node, 'length', { min: 1, max: 5000 }, path);
706
- break;
707
- }
708
- case 'cds.Decimal': {
709
- // Don't check with "plain"?
710
- if (node.precision || node.scale) {
711
- checkTypeParamValue(node, 'precision', { max: 38 }, path);
712
- checkTypeParamValue(node, 'scale', { max: node.precision }, path);
713
- }
714
- break;
715
- }
716
-
717
- case 'cds.hana.BINARY':
718
- case 'cds.hana.NCHAR':
719
- case 'cds.hana.CHAR': {
720
- checkTypeParamValue(node, 'length', { min: 1, max: 2000 }, path);
721
- break;
722
- }
723
- case 'cds.hana.ST_POINT':
724
- case 'cds.hana.ST_GEOMETRY': {
725
- checkTypeParamValue(node, 'srid', { max: Number.MAX_SAFE_INTEGER }, path);
726
- break;
727
- }
728
- case 'cds.Map': {
729
- if (options.sqlDialect === 'plain')
730
- error('ref-unsupported-type', path, { '#': 'dialect', type: node.type, value: 'plain' });
731
- else if (options.transformation === 'hdbcds')
732
- error('ref-unsupported-type', path, { '#': 'hdbcds', type: node.type, value: options.sqlDialect });
733
- break;
734
- }
735
- case 'cds.Vector': {
736
- if (options.sqlDialect === 'plain') {
737
- error('ref-unsupported-type', path, {
738
- '#': 'dialect',
739
- type: node.type,
740
- value: options.sqlDialect,
741
- });
742
- }
743
- else if (options.transformation === 'hdbcds') {
744
- error('ref-unsupported-type', path, {
745
- '#': 'hdbcds', type: node.type, value: options.sqlDialect,
746
- });
747
- }
748
- // Technical limitation of SQLite vector extension
749
- else if (options.sqlDialect === 'sqlite' && node.length && node.length % 4 !== 0) {
750
- error('ref-unexpected-args', path, {
751
- '#': 'vector_length', elemref: path.at(-1),
752
- });
753
- }
754
- break;
755
- }
756
- default:
757
- break; // nothing to check for unknown types
758
- }
759
- }
760
-
761
- // Check that the value of the type property `paramName` (e.g. length, precision, scale ...) is of `expectedType`
762
- // (which can currently only be 'positiveInteger') and (optional) the value is in a given range
763
- function checkTypeParamValue(node, paramName, range = null, path = null) {
764
- const paramValue = node[paramName];
765
- if (paramValue == null) {
766
- if (options.toSql || artifact.query || ![ 'cds.Binary', 'cds.hana.BINARY', 'cds.hana.NCHAR', 'cds.hana.CHAR' ].includes(node.type))
767
- return true;
768
-
769
- return error('type-missing-argument', path, { name: paramName, id: node.type, $reviewed: false });
770
- }
771
- if (range) {
772
- if (isMaxParameterLengthRestricted(node.type) && range.max && paramValue > range.max) {
773
- error('type-unexpected-argument', path, {
774
- '#': 'max', prop: paramName, type: node.type, number: range.max, $reviewed: false,
775
- });
776
- return false;
777
- }
778
- if (range.min && paramValue < range.min) {
779
- error('type-unexpected-argument', path, {
780
- '#': 'min', prop: paramName, type: node.type, number: range.min, $reviewed: false,
781
- });
782
- return false;
783
- }
784
- }
785
- return true;
786
- }
787
- }
788
576
 
789
577
  /**
790
- * Check if the maximum length of the value of the given type is restricted.
791
- *
792
- * @param {string} type
793
- * @returns {boolean}
794
- */
795
- function isMaxParameterLengthRestricted(type) {
796
- return !(options.toSql && type === 'cds.String' && (options.sqlDialect === 'sqlite' || options.sqlDialect === 'plain'));
797
- }
798
578
 
799
- /**
800
- * Flatten technical configuration stuff
801
579
  *
802
580
  * @param {CSN.Artifact} art
803
581
  * @param {string} artName Artifact Name
@@ -861,6 +639,20 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
861
639
  }
862
640
  }
863
641
 
642
+ function defHasCalculatedElements(def) {
643
+ return _hasCalcElement(def.elements);
644
+ }
645
+
646
+ function _hasCalcElement(elements) {
647
+ for (const name in elements) {
648
+ if (elements[name].$calc)
649
+ return true;
650
+ if (elements[name].elements && _hasCalcElement(elements[name].elements))
651
+ return true;
652
+ }
653
+ return false;
654
+ }
655
+
864
656
  module.exports = {
865
657
  transformForRelationalDBWithCsn,
866
658
  };