@sap/cds-compiler 6.1.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/bin/cdsc.js +17 -6
  3. package/bin/cdsse.js +1 -1
  4. package/bin/cdsv2m.js +1 -1
  5. package/lib/api/main.js +29 -7
  6. package/lib/api/options.js +1 -1
  7. package/lib/base/builtins.js +9 -0
  8. package/lib/base/keywords.js +1 -1
  9. package/lib/base/message-registry.js +41 -10
  10. package/lib/base/messages.js +13 -6
  11. package/lib/base/model.js +1 -1
  12. package/lib/base/optionProcessorHelper.js +7 -2
  13. package/lib/checks/assocOutsideService.js +17 -30
  14. package/lib/checks/checkForTypes.js +0 -18
  15. package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
  16. package/lib/checks/featureFlags.js +4 -1
  17. package/lib/checks/onConditions.js +2 -2
  18. package/lib/checks/queryNoDbArtifacts.js +16 -15
  19. package/lib/checks/types.js +1 -1
  20. package/lib/checks/utils.js +30 -6
  21. package/lib/checks/validator.js +4 -5
  22. package/lib/compiler/assert-consistency.js +3 -1
  23. package/lib/compiler/base.js +1 -1
  24. package/lib/compiler/builtins.js +1 -1
  25. package/lib/compiler/checks.js +85 -39
  26. package/lib/compiler/define.js +24 -5
  27. package/lib/compiler/extend.js +1 -1
  28. package/lib/compiler/finalize-parse-cdl.js +9 -1
  29. package/lib/compiler/generate.js +4 -4
  30. package/lib/compiler/index.js +88 -6
  31. package/lib/compiler/lsp-api.js +2 -0
  32. package/lib/compiler/populate.js +8 -8
  33. package/lib/compiler/propagator.js +1 -1
  34. package/lib/compiler/resolve.js +22 -21
  35. package/lib/compiler/shared.js +6 -6
  36. package/lib/compiler/tweak-assocs.js +53 -31
  37. package/lib/compiler/utils.js +9 -16
  38. package/lib/compiler/xpr-rewrite.js +2 -2
  39. package/lib/gen/BaseParser.js +35 -29
  40. package/lib/gen/CdlGrammar.checksum +1 -1
  41. package/lib/gen/CdlParser.js +1424 -1430
  42. package/lib/gen/Dictionary.json +1 -2
  43. package/lib/gen/cdlKeywords.json +26 -0
  44. package/lib/inspect/inspectPropagation.js +1 -1
  45. package/lib/json/from-csn.js +2 -2
  46. package/lib/json/to-csn.js +1 -1
  47. package/lib/language/multiLineStringParser.js +1 -1
  48. package/lib/model/cloneCsn.js +1 -0
  49. package/lib/model/csnRefs.js +9 -4
  50. package/lib/model/csnUtils.js +67 -2
  51. package/lib/optionProcessor.js +9 -9
  52. package/lib/parsers/AstBuildingParser.js +28 -26
  53. package/lib/parsers/identifiers.js +2 -30
  54. package/lib/render/toCdl.js +73 -13
  55. package/lib/render/toSql.js +127 -108
  56. package/lib/render/utils/common.js +4 -2
  57. package/lib/render/utils/sql.js +67 -0
  58. package/lib/transform/addTenantFields.js +4 -4
  59. package/lib/transform/db/assertUnique.js +2 -1
  60. package/lib/transform/db/associations.js +37 -1
  61. package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
  62. package/lib/transform/db/assocsToQueries/utils.js +1 -1
  63. package/lib/transform/db/cdsPersistence.js +1 -1
  64. package/lib/transform/db/expansion.js +37 -36
  65. package/lib/transform/db/killAnnotations.js +1 -0
  66. package/lib/transform/db/processSqlServices.js +20 -2
  67. package/lib/transform/draft/db.js +20 -20
  68. package/lib/transform/draft/odata.js +38 -40
  69. package/lib/transform/effective/associations.js +1 -1
  70. package/lib/transform/effective/flattening.js +40 -47
  71. package/lib/transform/effective/main.js +6 -4
  72. package/lib/transform/forOdata.js +201 -92
  73. package/lib/transform/forRelationalDB.js +151 -142
  74. package/lib/transform/localized.js +116 -109
  75. package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
  76. package/lib/transform/odata/createForeignKeys.js +73 -70
  77. package/lib/transform/odata/flattening.js +216 -200
  78. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
  79. package/lib/transform/odata/toFinalBaseType.js +40 -39
  80. package/lib/transform/odata/typesExposure.js +151 -133
  81. package/lib/transform/odata/utils.js +7 -6
  82. package/lib/transform/parseExpr.js +165 -162
  83. package/lib/transform/transformUtils.js +184 -551
  84. package/lib/transform/translateAssocsToJoins.js +511 -596
  85. package/lib/transform/tupleExpansion.js +495 -0
  86. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  87. package/lib/utils/moduleResolve.js +1 -1
  88. package/package.json +2 -2
  89. package/lib/base/cleanSymbols.js +0 -17
  90. package/lib/checks/nonexpandableStructured.js +0 -39
@@ -1,13 +1,16 @@
1
1
  'use strict';
2
2
 
3
3
  const { setProp, isBetaEnabled } = require('../base/model');
4
- const { forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
5
- getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
6
- walkCsnPath, isPersistedOnDatabase
7
- } = require('../model/csnUtils');
4
+ const {
5
+ forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
6
+ getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
7
+ walkCsnPath, isPersistedOnDatabase,
8
+ } = require('../model/csnUtils');
8
9
  const transformUtils = require('./transformUtils');
9
10
  const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
10
- const { csnRefs, pathId, traverseQuery, columnAlias} = require('../model/csnRefs');
11
+ const {
12
+ csnRefs, pathId, traverseQuery, columnAlias,
13
+ } = require('../model/csnRefs');
11
14
  const { checkCSNVersion } = require('../json/csnVersion');
12
15
  const validate = require('../checks/validator');
13
16
  const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../checks/selectItems');
@@ -33,11 +36,11 @@ const backlinks = require('./db/backlinks');
33
36
  const { getDefaultTypeLengths } = require('../render/utils/common');
34
37
  const { featureFlags } = require('./featureFlags');
35
38
  const { cloneCsnNonDict, cloneFullCsn } = require('../model/cloneCsn');
36
- const { processSqlServices, createServiceDummy } = require('./db/processSqlServices');
39
+ const { processSqlServices, createServiceDummy } = require('./db/processSqlServices');
37
40
 
38
41
  // By default: Do not process non-entities/views
39
42
  function forEachDefinition(csn, cb) {
40
- _forEachDefinition(csn, cb, {skip: ['annotation', 'action', 'function','event']})
43
+ _forEachDefinition(csn, cb, { skip: [ 'annotation', 'action', 'function', 'event' ] });
41
44
  }
42
45
 
43
46
  /**
@@ -129,10 +132,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
129
132
  /** @type {() => void} */
130
133
  let throwWithAnyError;
131
134
  // transformUtils
132
- let addDefaultTypeFacets,
133
- expandStructsInExpression,
134
- flattenStructuredElement,
135
- flattenStructStepsInRef;
135
+ let addDefaultTypeFacets;
136
+ let expandStructsInExpression;
137
+ let flattenStructuredElement;
138
+ let flattenStructStepsInRef;
136
139
 
137
140
  bindCsnReference();
138
141
 
@@ -163,12 +166,12 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
163
166
  // exit if validators found errors
164
167
  throwWithAnyError();
165
168
 
166
- if(csn.meta?.[featureFlags]?.$calculatedElements)
169
+ if (csn.meta?.[featureFlags]?.$calculatedElements)
167
170
  rewriteCalculatedElementsInViews(csn, options, csnUtils, pathDelimiter, messageFunctions);
168
171
 
169
172
  timetrace.start('Where-Exists handling');
170
173
  // Needs to happen before tuple expansion, so the newly generated WHERE-conditions have it applied
171
- handleExists(csn, options, error, csnUtils.inspectRef, csnUtils.initDefinition, csnUtils.dropDefinitionCache);
174
+ handleExists(csn, options, messageFunctions, csnUtils);
172
175
  timetrace.stop('Where-Exists handling');
173
176
 
174
177
  // Check if structured elements and managed associations are compared in an expression
@@ -179,17 +182,17 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
179
182
  timetrace.start('Expand Structures (expressions + refs)');
180
183
  // If this function is ever undefined, we have a bug in our logic.
181
184
  // @ts-ignore
182
- expandStructsInExpression(csn, { drillRef: true });
185
+ expandStructsInExpression({ drillRef: true });
183
186
 
184
187
  forEachDefinition(csn, [
185
188
  // (001) Add a temporal where condition to views where applicable before assoc2join
186
189
  // assoc2join eventually rewrites the table aliases
187
190
  temporal.getViewDecorator(csn, messageFunctions, csnUtils, options),
188
191
  // check unique constraints - further processing is done in rewriteUniqueConstraints
189
- assertUnique.prepare(csn, options, messageFunctions)
192
+ assertUnique.prepare(csn, options, messageFunctions),
190
193
  ]);
191
194
 
192
- if(doA2J) {
195
+ if (doA2J) {
193
196
  // Expand a structured thing in: keys, columns, order by, group by
194
197
  // In addition, kill all non-sql-backend relevant annotations
195
198
  expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils, { processAnnotations: true });
@@ -220,7 +223,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
220
223
  // With that, we could still ensure the processing order (assuming we don't run into problems with scoping).
221
224
  // To analyze: Increased memory vs. saved cycles
222
225
  // Looked at it with AFC: This is only a small part of the overall processing time, enrich step of validator is just as expensive
223
- if(doA2J) {
226
+ if (doA2J) {
224
227
  const resolved = new WeakMap();
225
228
  // No refs with struct-steps exist anymore
226
229
  flattening.flattenAllStructStepsInRefs(csn, options, messageFunctions, resolved, pathDelimiter);
@@ -229,7 +232,8 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
229
232
  flattening.resolveTypeReferences(csn, options, messageFunctions, resolved, pathDelimiter);
230
233
  // No structured elements exists anymore
231
234
  flattening.flattenElements(csn, options, messageFunctions, pathDelimiter);
232
- } else {
235
+ }
236
+ else {
233
237
  // For to.hdbcds with naming mode hdbcds we also need to resolve the types
234
238
  flattening.resolveTypeReferences(csn, options, messageFunctions, new WeakMap(), pathDelimiter);
235
239
  }
@@ -247,19 +251,19 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
247
251
  const redoProjections = [];
248
252
  // Use the "raw" forEachDefinition here to ensure that the $ignore takes effect
249
253
  _forEachDefinition(csn, (artifact) => {
250
- if(artifact.kind === 'entity' && artifact.projection) {
254
+ if (artifact.kind === 'entity' && artifact.projection) {
251
255
  artifact.query = { SELECT: artifact.projection };
252
256
  delete artifact.projection;
253
257
  redoProjections.push(() => {
254
- if(artifact.query) {
258
+ if (artifact.query) {
255
259
  artifact.projection = artifact.query.SELECT;
256
260
  delete artifact.query;
257
- if(artifact.$syntax === 'projection') {
261
+ if (artifact.$syntax === 'projection')
258
262
  delete artifact.$syntax;
259
- }
260
263
  }
261
- })
262
- } else if(artifact.kind === 'annotation' || artifact.kind === 'action' || artifact.kind === 'function' || artifact.kind === 'event'){
264
+ });
265
+ }
266
+ else if (artifact.kind === 'annotation' || artifact.kind === 'action' || artifact.kind === 'function' || artifact.kind === 'event') {
263
267
  // $ignore actions etc. - this loop seemed handy for this, as we can hook into an existing if
264
268
  artifact.$ignore = true;
265
269
  }
@@ -267,21 +271,20 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
267
271
 
268
272
  processCalculatedElementsInEntities(csn, options);
269
273
 
270
- timetrace.start('Transform CSN')
274
+ timetrace.start('Transform CSN');
271
275
 
272
276
  // Rename primitive types, make UUID a String; replace `items` by cds.LargeString
273
277
  //
274
278
  // First, gather all nodes that are arrayed: Don't replace inline, or getFinalTypeInfo()
275
279
  // may not return `.items` for types that were already processed.
276
280
  // TODO: Do this in resolveTypeReferences?
277
- {
278
- applyTransformations(csn, {
279
- type: (node) => {
280
- renamePrimitiveTypesAndUuid(node.type, node, 'type');
281
- addDefaultTypeFacets(node, implicitDefaultLengths);
282
- },
283
- });
284
- }
281
+ applyTransformations(csn, {
282
+ type: (node) => {
283
+ renamePrimitiveTypesAndUuid(node.type, node, 'type');
284
+ addDefaultTypeFacets(node, implicitDefaultLengths);
285
+ },
286
+ });
287
+
285
288
 
286
289
  forEachDefinition(csn, [
287
290
  // (040) Ignore entities and views that are abstract or implemented
@@ -290,24 +293,29 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
290
293
  cdsPersistence.getAnnoProcessor(),
291
294
  // (050) Check @cds.valid.from/to only on entity
292
295
  // Views are checked in (001), unbalanced valid.from/to's or mismatching origins
293
- temporal.getAnnotationHandler(csn, options, pathDelimiter, messageFunctions)
296
+ temporal.getAnnotationHandler(csn, options, pathDelimiter, messageFunctions),
294
297
  ]);
295
298
 
296
- // eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
297
- doA2J && flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, pathDelimiter, true, csnUtils, { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') });
298
-
299
- doA2J && forEachDefinition(csn, flattenIndexes);
300
- // Managed associations get an on-condition - in views and entities
301
- doA2J && associations.attachOnConditions(csn, csnUtils, pathDelimiter);
299
+ if (doA2J) {
300
+ // eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
301
+ flattening.handleManagedAssociationsAndCreateForeignKeys(
302
+ csn, options, messageFunctions, pathDelimiter, true, csnUtils,
303
+ { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') }
304
+ );
305
+ forEachDefinition(csn, flattenIndexes);
306
+ // Managed associations get an on-condition - in views and entities
307
+ associations.attachOnConditions(csn, csnUtils, pathDelimiter);
308
+ }
302
309
 
303
310
  {
304
311
  // (045) Strip all query-ish properties from views and projections annotated with '@cds.persistence.table',
305
312
  // and make them entities
306
- const fns = [cdsPersistence.getPersistenceTableProcessor(csn, options, messageFunctions)];
313
+ const fns = [ cdsPersistence.getPersistenceTableProcessor(csn, options, messageFunctions) ];
307
314
  // Allow using managed associations as steps in on-conditions to access their fks
308
315
  // To be done after handleAssociations, since then the foreign keys of the managed assocs
309
316
  // are part of the elements
310
- if(doA2J) fns.push(associations.getFKAccessFinalizer(csn, csnUtils, pathDelimiter));
317
+ if (doA2J)
318
+ fns.push(associations.getFKAccessFinalizer(csn, options, csnUtils, pathDelimiter));
311
319
 
312
320
  forEachDefinition(csn, fns);
313
321
  }
@@ -327,7 +335,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
327
335
  if (!doA2J && definition.query && isPersistedOnDatabase(definition)) {
328
336
  // reject managed association and structure publishing for to-hdbcds.hdbcds
329
337
  const that = { csnUtils, options, error };
330
- rejectManagedAssociationsAndStructuresForHdbcdsNames.call(that, definition, path)
338
+ rejectManagedAssociationsAndStructuresForHdbcdsNames.call(that, definition, path);
331
339
  }
332
340
  },
333
341
  // (170) Transform '$self' in backlink associations to appropriate key comparisons
@@ -335,7 +343,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
335
343
  // draft shadow entities have crooked '_artifact' links, confusing the backlink processing.
336
344
  // But it must also happen after flattenForeignKeys has been called for all artifacts,
337
345
  // because otherwise we would produce wrong ON-conditions for the keys involved. Sigh ...
338
- backlinks.getBacklinkTransformer(csnUtils, messageFunctions, options, pathDelimiter, doA2J)
346
+ backlinks.getBacklinkTransformer(csnUtils, messageFunctions, options, pathDelimiter, doA2J),
339
347
  ]);
340
348
 
341
349
  /**
@@ -343,7 +351,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
343
351
  * For to.hdbcds with naming mode "hdbcds", no foreign keys are calculated,
344
352
  * hence we do not generate the referential constraints for them.
345
353
  */
346
- if(options.sqlDialect !== 'plain' && options.sqlDialect !== 'h2' && doA2J)
354
+ if (options.sqlDialect !== 'plain' && options.sqlDialect !== 'h2' && doA2J)
347
355
  createReferentialConstraints(csn, options);
348
356
 
349
357
  // no constraints for drafts
@@ -360,24 +368,24 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
360
368
  messageFunctions.throwWithError();
361
369
 
362
370
  // TODO: Might have to do this earlier if we want special rendering for projections?
363
- const findAndMarkSqlServiceArtifacts = options.sqlDialect === 'hana' && options.src === 'hdi' && (csn.meta?.[featureFlags]?.$sqlService || csn.meta?.[featureFlags]?.$dummyService) ? processSqlServices(csn, options): () => {}
371
+ const findAndMarkSqlServiceArtifacts = options.sqlDialect === 'hana' && options.src === 'hdi' && (csn.meta?.[featureFlags]?.$sqlService || csn.meta?.[featureFlags]?.$dummyService || csn.meta?.[featureFlags]?.$dataProductService) ? processSqlServices(csn, options) : () => {};
364
372
 
365
373
  // Apply view-specific transformations
366
374
  // (160) Projections now finally become views
367
375
  // Replace managed association in group/order by with foreign keys
368
376
  const transformEntityOrViewPass2 = getViewTransformer(csn, options, messageFunctions);
369
- forEachDefinition(csn, [(artifact, artifactName) => {
377
+ forEachDefinition(csn, [ (artifact, artifactName) => {
370
378
  findAndMarkSqlServiceArtifacts(artifact, artifactName);
371
- if(artifact.$dummyService)
379
+ if (artifact.$dummyService)
372
380
  createServiceDummy(artifact, artifactName, csn, messageFunctions);
373
- }, transformViews]);
381
+ }, transformViews ]);
374
382
 
375
- if(!doA2J) {
383
+ if (!doA2J) {
376
384
  forEachDefinition(csn, [
377
385
  // (200) Strip 'key' property from type elements
378
386
  removeKeyPropInType,
379
387
  (artifact, artifactName) => {
380
- if(artifact.kind === 'type') {
388
+ if (artifact.kind === 'type') {
381
389
  forEachMemberRecursively(artifact, (member, memberName, prop, path) => {
382
390
  // Check type parameters (length, precision, scale ...)
383
391
  if (!member.$ignore) {
@@ -388,7 +396,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
388
396
  }
389
397
  }, [ 'definitions', artifactName ]);
390
398
  }
391
- }
399
+ },
392
400
  ]);
393
401
  }
394
402
 
@@ -409,55 +417,56 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
409
417
  csnUtils.addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(name, options.sqlMapping, options.sqlDialect), element);
410
418
  });
411
419
  // Remove leading $self to keep renderer-diffs smaller
412
- if(doA2J && options.transformation === 'hdbcds')
420
+ if (doA2J && options.transformation === 'hdbcds')
413
421
  flattening.removeLeadingSelf(parent, prop, elements);
414
- }
415
- }, [(definitions, artifactName, artifact) => {
422
+ },
423
+ }, [ (definitions, artifactName, artifact) => {
416
424
  // Attach @cds.persistence.name to artifacts
417
425
  if (!artifact.$ignore && artifact.kind !== 'service' && artifact.kind !== 'context')
418
426
  csnUtils.addStringAnnotationTo('@cds.persistence.name', getArtifactDatabaseNameOf(artifactName, options.sqlMapping, csn, options.sqlDialect), artifact);
419
- }], { allowArtifact: artifact => artifact.kind === 'entity'});
427
+ } ], { allowArtifact: artifact => artifact.kind === 'entity' });
420
428
 
421
429
  throwWithAnyError();
422
430
 
423
- function killProp(parent, prop){
431
+ function killProp(parent, prop) {
424
432
  delete parent[prop];
425
433
  }
426
434
 
427
- function killParent(parent, a, b, path){
428
- if(path.length > 2) {
429
- const tail = path[path.length-1];
430
- const parentPath = path.slice(0, -1)
435
+ function killParent(parent, a, b, path) {
436
+ if (path.length > 2) {
437
+ const tail = path[path.length - 1];
438
+ const parentPath = path.slice(0, -1);
431
439
  const parentParent = walkCsnPath(csn, parentPath);
432
440
  delete parentParent[tail];
433
- } else {
441
+ }
442
+ else {
434
443
  delete parent.$ignore;
435
444
  }
436
445
  }
437
446
 
438
447
  const killers = {
439
448
  // Used to ignore actions etc from processing and remove associations/elements
440
- '$ignore': killParent,
449
+ $ignore: killParent,
441
450
  // Still used in flattenStructuredElements - in db/flattening.js
442
- '_flatElementNameWithDots': killProp,
451
+ _flatElementNameWithDots: killProp,
443
452
  // Set when setting default string/binary length - used in copyTypeProperties and fixBorkedElementsOfLocalized
444
453
  // to not copy the .length property if it was only set via default
445
- '$default': killProp,
454
+ $default: killProp,
446
455
  // Set when we turn UUID into String, checked during generateDraftForHana
447
- '$renamed': killProp,
456
+ $renamed: killProp,
448
457
  // Set when we remove .key from temporal things, used in localized.js
449
- '$key': killProp,
458
+ $key: killProp,
450
459
  // We need .elements easily for rendering - otherwise we have to compute it then
451
460
  // Does not fit in the "killers" theme - TODO: Find a better place
452
461
  SET: (parent, prop, SET) => {
453
- if(!SET.elements) {
454
- const stack = [parent];
455
- while(stack.length > 0) {
462
+ if (!SET.elements) {
463
+ const stack = [ parent ];
464
+ while (stack.length > 0) {
456
465
  const query = stack.pop();
457
466
 
458
- if(query.SET)
467
+ if (query.SET)
459
468
  stack.push(query.SET.args[0]);
460
- else if(query.SELECT)
469
+ else if (query.SELECT)
461
470
  setProp(SET, 'elements', query.SELECT.elements);
462
471
  }
463
472
  }
@@ -465,34 +474,33 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
465
474
  includes: killProp,
466
475
  masked: killProp,
467
476
  localized: killProp,
468
- }
477
+ };
469
478
 
470
- if(options.sqlDialect === 'postgres') {
479
+ if (options.sqlDialect === 'postgres') {
471
480
  killers.length = (parent) => {
472
- if (parent.type === 'cds.Binary') {
481
+ if (parent.type === 'cds.Binary')
473
482
  delete parent.length;
474
- }
475
- }
483
+ };
476
484
  }
477
485
 
478
- if(options.sqlDialect === 'hana' && options.withHanaAssociations === false && doA2J) {
486
+ if (options.sqlDialect === 'hana' && options.withHanaAssociations === false && doA2J)
479
487
  killers.target = killParent;
480
- }
488
+
481
489
 
482
490
  const killTypes = [];
483
491
 
484
- if(doA2J) { // replace types and aspects with dummies to shrink overall CSN size
492
+ if (doA2J) { // replace types and aspects with dummies to shrink overall CSN size
485
493
  killers.kind = (parent, prop, kind, path) => {
486
- if(kind === 'type' || kind === 'aspect') {
494
+ if (kind === 'type' || kind === 'aspect') {
487
495
  const artifactName = path[1];
488
496
  killTypes.push(() => {
489
497
  csn.definitions[artifactName] = {
490
498
  kind,
491
- type: 'cds.Integer'
499
+ type: 'cds.Integer',
492
500
  };
493
- })
501
+ });
494
502
  }
495
- }
503
+ };
496
504
  }
497
505
 
498
506
  applyTransformations(csn, killers, [], { skipIgnore: false });
@@ -506,19 +514,20 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
506
514
 
507
515
  /* ----------------------------------- Functions start here -----------------------------------------------*/
508
516
 
509
- function bindCsnReference(){
517
+ function bindCsnReference() {
510
518
  messageFunctions.setModel(csn);
511
519
  ({ error, throwWithAnyError } = messageFunctions);
512
520
 
513
- ({ flattenStructuredElement,
521
+ ({
522
+ flattenStructuredElement,
514
523
  flattenStructStepsInRef,
515
524
  addDefaultTypeFacets,
516
525
  expandStructsInExpression,
517
- csnUtils
526
+ csnUtils,
518
527
  } = transformUtils.getTransformers(csn, options, messageFunctions, pathDelimiter));
519
528
  }
520
529
 
521
- function bindCsnReferenceOnly(){
530
+ function bindCsnReferenceOnly() {
522
531
  // invalidate caches for CSN ref API
523
532
  const csnRefApi = csnRefs(csn);
524
533
  Object.assign(csnUtils, csnRefApi);
@@ -533,45 +542,42 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
533
542
  if (mixin) {
534
543
  query.SELECT.columns
535
544
  // filter for associations which are used in the SELECT
536
- .filter((c) => {
537
- return c.ref && c.ref.length > 1;
538
- })
545
+ .filter(c => c.ref && c.ref.length > 1)
539
546
  .forEach((usedAssoc) => {
540
547
  const assocName = pathId(usedAssoc.ref[0]);
541
548
  const mixinAssociation = mixin[assocName];
542
549
  if (mixinAssociation)
543
- mixinAssociation.on = getResolvedMixinOnCondition(mixinAssociation, query, assocName, path.concat(['mixin', assocName]));
544
- })
550
+ mixinAssociation.on = getResolvedMixinOnCondition(mixinAssociation, query, assocName, path.concat([ 'mixin', assocName ]));
551
+ });
545
552
  }
546
- }, ['definitions', artifactName, 'query']);
553
+ }, [ 'definitions', artifactName, 'query' ]);
547
554
  }
548
555
 
549
556
  // For non-A2J only
550
557
  function getResolvedMixinOnCondition(mixinAssociation, query, assocName, path) {
551
- const referencedThroughStar = query.SELECT.columns.some((column) => column === '*');
558
+ const referencedThroughStar = query.SELECT.columns.some(column => column === '*');
552
559
  return mixinAssociation.on.map(handeMixinOnConditionPart);
553
560
 
554
- function handeMixinOnConditionPart(onConditionPart, i) {
561
+ function handeMixinOnConditionPart(onConditionPart, i) {
555
562
  let columnToReplace;
556
- if (onConditionPart.ref && (onConditionPart.ref[0] === '$projection' || onConditionPart.ref[0] === '$self')){
557
- const { links } = csnUtils.inspectRef(path.concat(['on', i]));
558
- if (links) {
563
+ if (onConditionPart.ref && (onConditionPart.ref[0] === '$projection' || onConditionPart.ref[0] === '$self')) {
564
+ const { links } = csnUtils.inspectRef(path.concat([ 'on', i ]));
565
+ if (links)
559
566
  columnToReplace = onConditionPart.ref[links.length - 1];
560
- }
561
567
  }
562
568
  if (!columnToReplace)
563
569
  return onConditionPart;
564
570
 
565
571
  const replaceWith = query.SELECT.columns.find(col => columnAlias(col) === columnToReplace);
566
572
  if (!replaceWith && referencedThroughStar) {
567
- // not explicitly in column list, check query sources
568
- // get$combined also includes elements which are part of "excluding {}"
569
- // this shouldn't be an issue here, as such references get rejected
573
+ // not explicitly in column list, check query sources
574
+ // get$combined also includes elements which are part of "excluding {}"
575
+ // this shouldn't be an issue here, as such references get rejected
570
576
  const elementsOfQuerySources = csnUtils.get$combined(query);
571
577
  forEach(elementsOfQuerySources, (id, element) => {
572
- // if the ref points to an element which is not explicitly exposed in the column list,
573
- // but through the '*' operator -> replace the $projection / $self with the correct source entity
574
- if(id === columnToReplace)
578
+ // if the ref points to an element which is not explicitly exposed in the column list,
579
+ // but through the '*' operator -> replace the $projection / $self with the correct source entity
580
+ if (id === columnToReplace)
575
581
  onConditionPart.ref[0] = element[0].parent;
576
582
  });
577
583
  return onConditionPart;
@@ -582,9 +588,8 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
582
588
  delete clone.as;
583
589
  return clone;
584
590
  }
585
- else {
586
- return onConditionPart
587
- }
591
+
592
+ return onConditionPart;
588
593
  }
589
594
  }
590
595
 
@@ -597,29 +602,29 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
597
602
  if (!artifact.$ignore) {
598
603
  // Do things specific for entities and views (pass 2)
599
604
  if ((artifact.kind === 'entity') && artifact.query) {
600
-
601
605
  // First pass: Set alias name for SELECTs without table alias. Required for setting proper table aliases
602
606
  // for HDBCDS in naming mode HDBCDS. We use the same schema as the core-compiler, so duplicates should
603
607
  // have already been reported.
604
- if(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds') {
608
+ if (options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds') {
605
609
  let selectDepth = 0;
606
610
  traverseQuery(artifact.query, null, null, (query, fromSelect) => {
607
611
  if (!query.ref && !query.as && fromSelect) {
608
612
  // Use +1; for UNION, it's the next select, for SELECT, it's increased later.
609
- query.as = `$_select_${selectDepth + 1}__`;
613
+ query.as = `$_select_${ selectDepth + 1 }__`;
610
614
  }
611
- if (query.SELECT) ++selectDepth;
615
+ if (query.SELECT)
616
+ ++selectDepth;
612
617
  });
613
618
  }
614
619
 
615
620
  const process = (parent, prop, query, path) => {
616
- transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop))
621
+ transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop));
617
622
  replaceAssociationsInGroupByOrderBy(parent, options, csnUtils.inspectRef, error, path.concat(prop));
618
623
  return query;
619
- }
624
+ };
620
625
  applyTransformationsOnNonDictionary(csn.definitions, artifactName, {
621
- SELECT: process
622
- }, {}, [ 'definitions']);
626
+ SELECT: process,
627
+ }, {}, [ 'definitions' ]);
623
628
  }
624
629
  }
625
630
  }
@@ -654,9 +659,9 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
654
659
 
655
660
  // restore all (non-enumerable) properties that wouldn't survive reaugmentation/compactification into the new compact model
656
661
  forEachDefinition(csn, (art, artName) => {
657
- if (art['$tableConstraints']) {
658
- newCsn.definitions[artName].$tableConstraints = art['$tableConstraints'];
659
- }
662
+ if (art.$tableConstraints)
663
+ newCsn.definitions[artName].$tableConstraints = art.$tableConstraints;
664
+
660
665
  if (art.technicalConfig)
661
666
  newCsn.definitions[artName].technicalConfig = art.technicalConfig;
662
667
  });
@@ -677,7 +682,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
677
682
  // assert key === 'type'
678
683
  const hanaNamesMap = {
679
684
  __proto__: null,
680
- 'cds.UUID': 'cds.String'
685
+ 'cds.UUID': 'cds.String',
681
686
  };
682
687
  node[key] = hanaNamesMap[val] || val;
683
688
  if (val === 'cds.UUID' && !node.length) {
@@ -685,9 +690,9 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
685
690
  setProp(node, '$renamed', 'cds.UUID');
686
691
  }
687
692
 
688
- if(options.sqlDialect === 'h2' && val === 'cds.Decimal' && node.scale === undefined) {
693
+ if (options.sqlDialect === 'h2' && val === 'cds.Decimal' && node.scale === undefined)
689
694
  node[key] = 'cds.DecimalFloat'; // cds.Decimal and cds.Decimal(p) should map do DECFLOAT for h2
690
- }
695
+
691
696
 
692
697
  // Length/Precision/Scale is done in addDefaultTypeFacets
693
698
  }
@@ -742,23 +747,27 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
742
747
  if (options.sqlDialect === 'plain')
743
748
  error('ref-unsupported-type', path, { '#': 'dialect', type: node.type, value: 'plain' });
744
749
  else if (options.transformation === 'hdbcds')
745
- error('ref-unsupported-type', path, {'#': 'hdbcds', type: node.type, value: options.sqlDialect });
750
+ error('ref-unsupported-type', path, { '#': 'hdbcds', type: node.type, value: options.sqlDialect });
746
751
  break;
747
752
  }
748
753
  case 'cds.Vector': {
749
754
  if (options.sqlDialect !== 'hana') {
750
755
  error('ref-unsupported-type', path, {
751
- '#': 'hana', type: node.type, value: 'hana',
752
- othervalue: options.sqlDialect
756
+ '#': 'hana',
757
+ type: node.type,
758
+ value: 'hana',
759
+ othervalue: options.sqlDialect,
753
760
  });
754
761
  }
755
762
  else if (options.transformation === 'hdbcds') {
756
763
  error('ref-unsupported-type', path, {
757
- '#': 'hdbcds', type: node.type, value: options.sqlDialect
764
+ '#': 'hdbcds', type: node.type, value: options.sqlDialect,
758
765
  });
759
766
  }
760
767
  break;
761
768
  }
769
+ default:
770
+ break; // nothing to check for unknown types
762
771
  }
763
772
  }
764
773
 
@@ -767,21 +776,22 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
767
776
  function checkTypeParamValue(node, paramName, range = null, path = null) {
768
777
  const paramValue = node[paramName];
769
778
  if (paramValue == null) {
770
- if(options.toSql || artifact.query || !['cds.Binary','cds.hana.BINARY', 'cds.hana.NCHAR','cds.hana.CHAR'].includes(node.type)) {
779
+ if (options.toSql || artifact.query || ![ 'cds.Binary', 'cds.hana.BINARY', 'cds.hana.NCHAR', 'cds.hana.CHAR' ].includes(node.type))
771
780
  return true;
772
- } else {
773
- return error('type-missing-argument', path, { name: paramName, id: node.type, $reviewed: false });
774
- }
781
+
782
+ return error('type-missing-argument', path, { name: paramName, id: node.type, $reviewed: false });
775
783
  }
776
784
  if (range) {
777
785
  if (isMaxParameterLengthRestricted(node.type) && range.max && paramValue > range.max) {
778
- error('type-unexpected-argument', path,
779
- { '#': 'max', prop: paramName, type: node.type, number: range.max, $reviewed: false });
786
+ error('type-unexpected-argument', path, {
787
+ '#': 'max', prop: paramName, type: node.type, number: range.max, $reviewed: false,
788
+ });
780
789
  return false;
781
790
  }
782
791
  if (range.min && paramValue < range.min) {
783
- error('type-unexpected-argument', path,
784
- { '#': 'min', prop: paramName, type: node.type, number: range.min, $reviewed: false });
792
+ error('type-unexpected-argument', path, {
793
+ '#': 'min', prop: paramName, type: node.type, number: range.min, $reviewed: false,
794
+ });
785
795
  return false;
786
796
  }
787
797
  }
@@ -816,9 +826,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
816
826
  if (Array.isArray(index)) {
817
827
  const flattenedIndex = [];
818
828
  const isFulltextIndex = (index[0] === 'fulltext');
819
- index.forEach((val, idx) => {
829
+ for (let idx = 0; idx < index.length; idx++) {
830
+ const val = index[idx];
820
831
  if (typeof val === 'object' && val.ref) {
821
- // Replace a reference by references to it's elements, if it is structured
832
+ // Replace a reference by references to its elements, if it is structured
822
833
  const path = [ 'definitions', artName, 'technicalConfig', dialect, 'indexes', name, idx ];
823
834
  const { art } = csnUtils.inspectRef(path);
824
835
  if (!art) {
@@ -832,7 +843,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
832
843
  // First, compute the name from the path, e.g ['s', 's1', 's2' ] will result in 'S_s1_s2' ...
833
844
  const [ refPath ] = flattenStructStepsInRef(val.ref, path);
834
845
  // ... and take this as the prefix for all elements
835
- const flattenedElems = flattenStructuredElement(art, refPath, [], ['definitions', artName, 'elements']);
846
+ const flattenedElems = flattenStructuredElement(art, refPath, [], [ 'definitions', artName, 'elements' ]);
836
847
  Object.keys(flattenedElems).forEach((elem, i, elems) => {
837
848
  // if it's not the first entry, add a ',' ...
838
849
  if (i)
@@ -850,11 +861,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
850
861
  flattenedIndex.push({ ref: refPath });
851
862
  }
852
863
  }
853
- else // it's just some token like 'index', '(' etc. so we copy it over
854
- {
864
+ else { // it's just some token like 'index', '(' etc. so we copy it over
855
865
  flattenedIndex.push(val);
856
866
  }
857
- });
867
+ }
858
868
  // Replace index by the flattened one
859
869
  tc[dialect].indexes[name] = flattenedIndex;
860
870
  }
@@ -862,7 +872,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
862
872
  }
863
873
  }
864
874
  }
865
-
866
875
  }
867
876
 
868
877
  module.exports = {