@sap/cds-compiler 4.4.4 → 4.6.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 (82) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/bin/cdsc.js +18 -11
  3. package/bin/cdsv2m.js +7 -5
  4. package/doc/CHANGELOG_BETA.md +22 -0
  5. package/lib/api/main.js +306 -144
  6. package/lib/api/options.js +18 -6
  7. package/lib/api/validate.js +1 -1
  8. package/lib/base/message-registry.js +45 -10
  9. package/lib/base/messages.js +33 -16
  10. package/lib/base/model.js +4 -0
  11. package/lib/base/optionProcessorHelper.js +45 -176
  12. package/lib/checks/annotationsOData.js +49 -0
  13. package/lib/checks/elements.js +32 -34
  14. package/lib/checks/enricher.js +39 -3
  15. package/lib/checks/validator.js +8 -7
  16. package/lib/compiler/assert-consistency.js +40 -17
  17. package/lib/compiler/builtins.js +30 -53
  18. package/lib/compiler/checks.js +46 -14
  19. package/lib/compiler/cycle-detector.js +1 -4
  20. package/lib/compiler/define.js +35 -10
  21. package/lib/compiler/extend.js +21 -7
  22. package/lib/compiler/generate.js +3 -0
  23. package/lib/compiler/populate.js +5 -1
  24. package/lib/compiler/propagator.js +46 -9
  25. package/lib/compiler/resolve.js +94 -35
  26. package/lib/compiler/shared.js +60 -33
  27. package/lib/compiler/tweak-assocs.js +188 -92
  28. package/lib/compiler/utils.js +11 -1
  29. package/lib/edm/annotations/edmJson.js +41 -66
  30. package/lib/edm/annotations/genericTranslation.js +27 -9
  31. package/lib/edm/annotations/preprocessAnnotations.js +2 -3
  32. package/lib/edm/csn2edm.js +28 -11
  33. package/lib/edm/edmInboundChecks.js +58 -15
  34. package/lib/edm/edmPreprocessor.js +12 -16
  35. package/lib/edm/edmUtils.js +5 -2
  36. package/lib/gen/Dictionary.json +10 -0
  37. package/lib/gen/language.checksum +1 -1
  38. package/lib/gen/language.interp +15 -2
  39. package/lib/gen/language.tokens +1 -0
  40. package/lib/gen/languageParser.js +6557 -5618
  41. package/lib/json/from-csn.js +4 -5
  42. package/lib/json/to-csn.js +29 -4
  43. package/lib/language/antlrParser.js +19 -1
  44. package/lib/language/errorStrategy.js +28 -7
  45. package/lib/language/genericAntlrParser.js +118 -24
  46. package/lib/language/textUtils.js +16 -0
  47. package/lib/main.d.ts +28 -3
  48. package/lib/main.js +3 -0
  49. package/lib/model/csnRefs.js +4 -1
  50. package/lib/model/csnUtils.js +20 -14
  51. package/lib/model/revealInternalProperties.js +5 -2
  52. package/lib/optionProcessor.js +23 -22
  53. package/lib/render/manageConstraints.js +13 -29
  54. package/lib/render/toCdl.js +47 -26
  55. package/lib/render/toHdbcds.js +63 -42
  56. package/lib/render/toRename.js +6 -10
  57. package/lib/render/toSql.js +71 -117
  58. package/lib/render/utils/common.js +41 -6
  59. package/lib/transform/.eslintrc.json +9 -1
  60. package/lib/transform/addTenantFields.js +228 -0
  61. package/lib/transform/db/applyTransformations.js +57 -4
  62. package/lib/transform/db/assertUnique.js +4 -4
  63. package/lib/transform/db/backlinks.js +13 -1
  64. package/lib/transform/db/cdsPersistence.js +1 -1
  65. package/lib/transform/db/expansion.js +24 -3
  66. package/lib/transform/db/flattening.js +70 -71
  67. package/lib/transform/db/killAnnotations.js +37 -0
  68. package/lib/transform/db/rewriteCalculatedElements.js +46 -6
  69. package/lib/transform/db/temporal.js +1 -1
  70. package/lib/transform/draft/db.js +2 -16
  71. package/lib/transform/draft/odata.js +3 -3
  72. package/lib/transform/effective/associations.js +3 -5
  73. package/lib/transform/effective/main.js +6 -9
  74. package/lib/transform/forOdata.js +26 -55
  75. package/lib/transform/forRelationalDB.js +38 -18
  76. package/lib/transform/odata/toFinalBaseType.js +3 -3
  77. package/lib/transform/odata/typesExposure.js +14 -5
  78. package/lib/transform/transformUtils.js +47 -34
  79. package/lib/transform/translateAssocsToJoins.js +45 -11
  80. package/lib/transform/universalCsn/coreComputed.js +1 -1
  81. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  82. package/package.json +7 -6
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const { makeMessageFunction } = require('../base/messages');
4
3
  const { isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
5
4
  const transformUtils = require('./transformUtils');
6
5
  const { cloneCsnNonDict,
@@ -24,6 +23,7 @@ const associations = require('./db/associations')
24
23
  const expansion = require('./db/expansion');
25
24
  const generateDrafts = require('./draft/odata');
26
25
 
26
+ const { addTenantFields } = require('./addTenantFields');
27
27
  const { addLocalizationViews } = require('./localized');
28
28
 
29
29
  // Transformation for ODATA. Expects a CSN 'inputModel', processes it for ODATA.
@@ -68,23 +68,22 @@ const { addLocalizationViews } = require('./localized');
68
68
  // (Linter check candidate)
69
69
  module.exports = { transform4odataWithCsn };
70
70
 
71
- function transform4odataWithCsn(inputModel, options) {
71
+ function transform4odataWithCsn(inputModel, options, messageFunctions) {
72
72
  timetrace.start('OData transformation');
73
73
 
74
74
  // copy the model as we don't want to change the input model
75
75
  let csn = cloneCsnNonDict(inputModel, options);
76
+ messageFunctions.setModel(csn);
76
77
 
77
- const { message, error, warning, info, throwWithAnyError } = makeMessageFunction(csn, options, 'for.odata');
78
+ const { message, error, warning, info, throwWithAnyError } = messageFunctions;
78
79
  throwWithAnyError();
79
80
 
80
81
  // the new transformer works only with new CSN
81
82
  checkCSNVersion(csn, options);
82
83
 
83
- const transformers = transformUtils.getTransformers(csn, options, '_');
84
+ const transformers = transformUtils.getTransformers(csn, options, messageFunctions, '_');
84
85
  const {
85
- addDefaultTypeFacets,
86
- extractValidFromToKeyElement,
87
- checkAssignment, checkMultipleAssignments,
86
+ addDefaultTypeFacets, checkMultipleAssignments,
88
87
  recurseElements, setAnnotation, renameAnnotation,
89
88
  expandStructsInExpression,
90
89
  csnUtils,
@@ -119,6 +118,9 @@ function transform4odataWithCsn(inputModel, options) {
119
118
  if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
120
119
  enrichUniversalCsn(csn, options);
121
120
 
121
+ if (options.tenantAsColumn)
122
+ addTenantFields(csn, options);
123
+
122
124
  const keepLocalizedViews = isDeprecatedEnabled(options, '_createLocalizedViews');
123
125
 
124
126
  function acceptLocalizedView(_name, parent) {
@@ -132,17 +134,17 @@ function transform4odataWithCsn(inputModel, options) {
132
134
  transformUtils.rewriteBuiltinTypeRef(csn);
133
135
 
134
136
  const cleanup = validate.forOdata(csn, {
135
- message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef, csn, options, csnUtils, services, isAspect, isExternalServiceMember
137
+ message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef,
138
+ options, csnUtils, services, isAspect, isExternalServiceMember, recurseElements,
139
+ checkMultipleAssignments, csn,
136
140
  });
137
141
 
138
142
 
139
143
  // Throw exception in case of errors
140
144
  throwWithAnyError();
141
145
 
142
- // Semantic checks before flattening regarding temporal data
143
- // TODO: Move in the validator
146
+ // TODO: Refactor out the following logic
144
147
  forEachDefinition(csn, [
145
- checkTemporalAnnotationsAssignment,
146
148
  (def) => {
147
149
  // Convert a projection into a query for internal processing will be re-converted
148
150
  // at the end of the OData processing
@@ -175,21 +177,20 @@ function transform4odataWithCsn(inputModel, options) {
175
177
  // If errors are detected, throwWithAnyError() will return from further processing
176
178
  expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
177
179
 
178
-
179
180
  if (!structuredOData) {
180
181
  expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, csnUtils, { skipArtifact: isExternalServiceMember });
181
182
  const resolved = new WeakMap();
182
183
  // No refs with struct-steps exist anymore
183
184
 
184
- flattening.flattenAllStructStepsInRefs(csn, options, resolved, '_', { skipArtifact: isExternalServiceMember });
185
+ flattening.flattenAllStructStepsInRefs(csn, options, messageFunctions, resolved, '_', { skipArtifact: isExternalServiceMember });
185
186
  // No type references exist anymore
186
187
  // Needs to happen exactly between flattenAllStructStepsInRefs and flattenElements to keep model resolvable.
187
188
  // OData doesn't resolve type chains after the first 'items'
188
- flattening.resolveTypeReferences(csn, options, resolved, '_',
189
+ flattening.resolveTypeReferences(csn, options, messageFunctions, resolved, '_',
189
190
  { skip: [ 'action', 'aspect', 'event', 'function', 'type'],
190
191
  skipArtifact: isExternalServiceMember, skipStandard: { items: true } });
191
192
  // No structured elements exists anymore
192
- flattening.flattenElements(csn, options, '_', error,
193
+ flattening.flattenElements(csn, options, messageFunctions, '_',
193
194
  { skip: ['action', 'aspect', 'event', 'function', 'type'],
194
195
  skipArtifact: isExternalServiceMember,
195
196
  skipStandard: { items: true }, // don't drill further into .items
@@ -198,7 +199,7 @@ function transform4odataWithCsn(inputModel, options) {
198
199
 
199
200
  // TODO: add the generated foreign keys to the columns when we are in a view
200
201
  // see db/views.js::addForeignKeysToColumns
201
- flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, warning, '_', !structuredOData, csnUtils,{ skipArtifact: isExternalServiceMember });
202
+ flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, '_', !structuredOData, csnUtils,{ skipArtifact: isExternalServiceMember });
202
203
 
203
204
  // Allow using managed associations as steps in on-conditions to access their fks
204
205
  // To be done after handleManagedAssociationsAndCreateForeignKeys,
@@ -272,7 +273,7 @@ function transform4odataWithCsn(inputModel, options) {
272
273
 
273
274
  // Convert a query back into a projection for CSN compliance as
274
275
  // the very last conversion step of the OData transformation
275
- if (def.kind === 'entity' && def.query && def.query && def.projection) {
276
+ if (def.kind === 'entity' && def.query && def.projection) {
276
277
  delete def.query;
277
278
  }
278
279
  }, { skipArtifact: isExternalServiceMember })
@@ -288,29 +289,6 @@ function transform4odataWithCsn(inputModel, options) {
288
289
  timetrace.stop('OData transformation');
289
290
  return csn;
290
291
 
291
- // TODO: Move this to checks?
292
- // @ts-ignore
293
- function checkTemporalAnnotationsAssignment(artifact, artifactName, propertyName, path) {
294
- // Gather all element names with @cds.valid.from/to/key
295
- let validFrom = [], validTo = [], validKey = [];
296
- recurseElements(artifact, ['definitions', artifactName], (member, path) => {
297
- let [f, t, k] = extractValidFromToKeyElement(member, path);
298
- validFrom.push(...f);
299
- validTo.push(...t);
300
- validKey.push(...k);
301
- });
302
- // Check that @cds.valid.from/to/key is only in valid places
303
- validFrom.forEach(obj => checkAssignment('@cds.valid.from', obj.element, obj.path, artifact));
304
- validTo.forEach(obj => checkAssignment('@cds.valid.to', obj.element, obj.path, artifact));
305
- validKey.forEach(obj => checkAssignment('@cds.valid.key', obj.element, obj.path, artifact));
306
- checkMultipleAssignments(validFrom, '@cds.valid.from', artifact, artifactName);
307
- checkMultipleAssignments(validTo, '@cds.valid.to', artifact, artifactName);
308
- checkMultipleAssignments(validKey, '@cds.valid.key', artifact, artifactName);
309
- if (validKey.length && !(validFrom.length && validTo.length)) {
310
- error(null, path, 'Annotation “@cds.valid.key” was used but “@cds.valid.from” and “@cds.valid.to” are missing');
311
- }
312
- }
313
-
314
292
  // Mark elements that are annotated with @odata.on.insert/update with the annotation @Core.Computed.
315
293
  function annotateCoreComputed(node) {
316
294
  // If @Core.Computed is explicitly set, don't overwrite it!
@@ -347,7 +325,7 @@ function transform4odataWithCsn(inputModel, options) {
347
325
  return;
348
326
  // Rename according to map above
349
327
  const renamePrefix = (name in renameMappings)
350
- ? name
328
+ ? name
351
329
  : renameShortCuts.find(p => name.startsWith(p + '.'));
352
330
  if(renamePrefix) {
353
331
  const mapping = renameMappings[renamePrefix];
@@ -442,25 +420,18 @@ function transform4odataWithCsn(inputModel, options) {
442
420
  }
443
421
  }
444
422
 
445
- // CDXCORE-481
446
423
  // (4.5) If the member is an association whose target has @cds.odata.valuelist annotate it
447
424
  // with @Common.ValueList.viaAssociation.
448
- /*
449
- FIXME (HJB): Comment outdated: Anno propagation to FKs is done in EdmPreprocessor
450
- */
451
- // This must be done before foreign keys are calculated and the annotations are propagated
452
- // to them. This will make sure that association and all its foreign keys are annotated with
453
- // Common.ValueList in the final EDM.
454
- // Do this only if the association is navigable and the enclosing artifact is
455
- // a service member (don't pollute the CSN with unnecessary annotations).
456
- // TODO: test???
425
+ // Do this only if the association is navigable(@odata.navigable) and the enclosing artifact is
426
+ // a service member (don't pollute the CSN with unnecessary annotations, that is ensured by the caller
427
+ // of this function).
457
428
  function addCommonValueListviaAssociation(member, memberName) {
458
- let vlAnno = '@Common.ValueList.viaAssociation';
429
+ const vlAnno = '@Common.ValueList.viaAssociation';
459
430
  if (isAssociation(member)) {
460
- let navigable = member['@odata.navigable'] !== false; // navigable disabled only if explicitly set to false
461
- let targetDef = getCsnDef(member.target);
431
+ const navigable = member['@odata.navigable'] !== false; // navigable disabled only if explicitly set to false
432
+ const targetDef = getCsnDef(member.target);
462
433
  if (navigable && targetDef['@cds.odata.valuelist'] && !member[vlAnno]) {
463
- member[vlAnno] = { '=': memberName };
434
+ setAnnotation(member, vlAnno, { '=': memberName });
464
435
  }
465
436
  }
466
437
  }
@@ -6,13 +6,13 @@ const { cloneCsnNonDict,
6
6
  getArtifactDatabaseNameOf, getElementDatabaseNameOf, isBuiltinType, applyTransformations,
7
7
  isAspect, walkCsnPath, isPersistedOnDatabase
8
8
  } = require('../model/csnUtils');
9
- const { makeMessageFunction } = require('../base/messages');
10
9
  const transformUtils = require('./transformUtils');
11
10
  const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
12
11
  const { csnRefs, pathId, traverseQuery, columnAlias} = require('../model/csnRefs');
13
12
  const { checkCSNVersion } = require('../json/csnVersion');
14
13
  const validate = require('../checks/validator');
15
14
  const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../checks/selectItems');
15
+ const { addTenantFields } = require('../transform/addTenantFields');
16
16
  const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
17
17
  const { timetrace } = require('../utils/timetrace');
18
18
  const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
@@ -100,9 +100,9 @@ function forEachDefinition(csn, cb) {
100
100
  *
101
101
  * @param {CSN.Model} csn
102
102
  * @param {CSN.Options} options
103
- * @param {string} moduleName The calling compiler module name, e.g. `to.hdi` or `to.hdbcds`.
103
+ * @param {object} messageFunctions Message functions such as `error()`, `info()`,
104
104
  */
105
- function transformForRelationalDBWithCsn(csn, options, moduleName) {
105
+ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
106
106
  // copy the model as we don't want to change the input model
107
107
  timetrace.start('HANA transformation');
108
108
 
@@ -111,6 +111,9 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
111
111
  csn = cloneCsnNonDict(csn, options);
112
112
  timetrace.stop('Clone CSN');
113
113
 
114
+ if (options.tenantAsColumn)
115
+ addTenantFields(csn, options);
116
+
114
117
  checkCSNVersion(csn, options);
115
118
 
116
119
  const pathDelimiter = (options.sqlMapping === 'hdbcds') ? '.' : '_';
@@ -120,12 +123,11 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
120
123
  /** @type {object} */
121
124
  let csnUtils;
122
125
  /** @type {object} */
123
- let messageFunctions;
124
- let message, error, warning, info; // message functions
126
+ let message, error, warning; // message functions
125
127
  /** @type {() => void} */
126
128
  let throwWithAnyError;
127
129
  // transformUtils
128
- let addDefaultTypeFacets,
130
+ let addDefaultTypeFacets,
129
131
  expandStructsInExpression,
130
132
  flattenStructuredElement,
131
133
  flattenStructStepsInRef;
@@ -180,12 +182,13 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
180
182
  // assoc2join eventually rewrites the table aliases
181
183
  temporal.getViewDecorator(csn, messageFunctions, csnUtils),
182
184
  // check unique constraints - further processing is done in rewriteUniqueConstraints
183
- assertUnique.prepare(csn, options, error, info)
185
+ assertUnique.prepare(csn, options, messageFunctions)
184
186
  ]);
185
187
 
186
188
  if(doA2J) {
187
189
  // Expand a structured thing in: keys, columns, order by, group by
188
- expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils);
190
+ // In addition, kill all non-sql-backend relevant annotations
191
+ expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils, { processAnnotations: true });
189
192
  bindCsnReference();
190
193
  }
191
194
 
@@ -203,15 +206,15 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
203
206
  if(doA2J) {
204
207
  const resolved = new WeakMap();
205
208
  // No refs with struct-steps exist anymore
206
- flattening.flattenAllStructStepsInRefs(csn, options, resolved, pathDelimiter);
209
+ flattening.flattenAllStructStepsInRefs(csn, options, messageFunctions, resolved, pathDelimiter);
207
210
  // No type references exist anymore
208
211
  // Needs to happen exactly between flattenAllStructStepsInRefs and flattenElements to keep model resolvable.
209
- flattening.resolveTypeReferences(csn, options, resolved, pathDelimiter);
212
+ flattening.resolveTypeReferences(csn, options, messageFunctions, resolved, pathDelimiter);
210
213
  // No structured elements exists anymore
211
- flattening.flattenElements(csn, options, pathDelimiter, error);
214
+ flattening.flattenElements(csn, options, messageFunctions, pathDelimiter);
212
215
  } else {
213
216
  // For to.hdbcds with naming mode hdbcds we also need to resolve the types
214
- flattening.resolveTypeReferences(csn, options, new WeakMap(), pathDelimiter);
217
+ flattening.resolveTypeReferences(csn, options, messageFunctions, new WeakMap(), pathDelimiter);
215
218
  }
216
219
 
217
220
  // With flattening errors, it makes little sense to continue.
@@ -284,7 +287,7 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
284
287
  ]);
285
288
 
286
289
  // eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
287
- doA2J && flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, warning, pathDelimiter, true, csnUtils, { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') });
290
+ doA2J && flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, pathDelimiter, true, csnUtils, { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') });
288
291
 
289
292
  doA2J && forEachDefinition(csn, flattenIndexes);
290
293
  // Managed associations get an on-condition - in views and entities
@@ -357,6 +360,9 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
357
360
  // Associations that point to things marked with @cds.persistence.skip are removed
358
361
  forEachDefinition(csn, cdsPersistence.getAssocToSkippedIgnorer(csn, options, messageFunctions, csnUtils));
359
362
 
363
+ // some errors can't be handled in the subsequent processing steps for e.g. HDBCDS
364
+ messageFunctions.throwWithError();
365
+
360
366
  // Apply view-specific transformations
361
367
  // (160) Projections now finally become views
362
368
  // Replace managed association in group/order by with foreign keys
@@ -448,15 +454,15 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
448
454
  /* ----------------------------------- Functions start here -----------------------------------------------*/
449
455
 
450
456
  function bindCsnReference(){
451
- messageFunctions = makeMessageFunction(csn, options, moduleName);
452
- ({ error, warning, info, message, throwWithAnyError } = messageFunctions);
457
+ messageFunctions.setModel(csn);
458
+ ({ error, warning, message, throwWithAnyError } = messageFunctions);
453
459
 
454
460
  ({ flattenStructuredElement,
455
461
  flattenStructStepsInRef,
456
462
  addDefaultTypeFacets,
457
463
  expandStructsInExpression,
458
464
  csnUtils
459
- } = transformUtils.getTransformers(csn, options, pathDelimiter));
465
+ } = transformUtils.getTransformers(csn, options, messageFunctions, pathDelimiter));
460
466
  }
461
467
 
462
468
  function bindCsnReferenceOnly(){
@@ -613,10 +619,10 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
613
619
  // (100 a) Ignore the property 'masked' itself (but not its effect on projections)
614
620
  if (member.masked)
615
621
  delete member.masked;
616
- // For HANA: Report an error on
622
+ // Report an error on
617
623
  // - view with parameters that has an element of type association/composition
618
624
  // - association that points to entity with parameters
619
- if (options.sqlDialect === 'hana' && member.target && csnUtils.isAssocOrComposition(member) && !isBetaEnabled(options, 'assocsWithParams')) {
625
+ if (member.target && csnUtils.isAssocOrComposition(member) && !isBetaEnabled(options, 'assocsWithParams')) {
620
626
  if (artifact.params) {
621
627
  // HANA does not allow 'WITH ASSOCIATIONS' on something with parameters:
622
628
  // SAP DBTech JDBC: [7]: feature not supported: parameterized sql view cannot support association: line 1 col 1 (at pos 0)
@@ -861,6 +867,20 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
861
867
  checkTypeParamValue(node, 'srid', { max: Number.MAX_SAFE_INTEGER }, path);
862
868
  break;
863
869
  }
870
+ case 'cds.Vector': {
871
+ if (options.sqlDialect !== 'hana') {
872
+ error('ref-unsupported-type', path, {
873
+ '#': 'hana', type: node.type, value: 'hana',
874
+ othervalue: options.sqlDialect
875
+ });
876
+ }
877
+ else if (options.transformation === 'hdbcds') {
878
+ error('ref-unsupported-type', path, {
879
+ '#': 'hdbcds', type: node.type, value: options.sqlDialect
880
+ });
881
+ }
882
+ break;
883
+ }
864
884
  }
865
885
  }
866
886
 
@@ -7,7 +7,7 @@ const {
7
7
  } = require('../../model/csnUtils');
8
8
  const { isArtifactInSomeService, isArtifactInService } = require('./utils');
9
9
 
10
- function expandToFinalBaseType(csn, transformers, csnUtils, services, options, isExternalServiceMember) {
10
+ function expandToFinalBaseType(csn, transformers, csnUtils, services, options) {
11
11
  const isV4 = options.odataVersion === 'v4';
12
12
  const special$self = !csn?.definitions?.$self && '$self';
13
13
  forEachDefinition(csn, (def, defName) => {
@@ -63,7 +63,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
63
63
  if (def.kind === 'type' && def.items && isArtifactInSomeService(defName, services)) {
64
64
  expandFirstLevelOfArrayed(def);
65
65
  }
66
- }, { skipArtifact: isExternalServiceMember });
66
+ });
67
67
 
68
68
  if(isBetaEnabled(options, 'odataTerms')) {
69
69
  forEachGeneric(csn, 'vocabularies', (def, defName) => {
@@ -75,7 +75,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
75
75
 
76
76
  expandToFinalBaseType(def, defName);
77
77
  expandToFinalBaseType(def.items, defName);
78
- }, [], { skipArtifact: isExternalServiceMember });
78
+ }, []);
79
79
  }
80
80
  // In case we have in the model something like:
81
81
  // type Foo: array of Bar; type Bar: { qux: Integer };
@@ -6,11 +6,11 @@
6
6
  * @module typesExposure
7
7
  */
8
8
 
9
- const { setProp } = require('../../base/model');
9
+ const { setProp, isBetaEnabled } = require('../../base/model');
10
10
  const { defNameWithoutServiceOrContextName, isArtifactInService } = require('./utils');
11
- const { cloneCsnNonDict, isBuiltinType, forEachDefinition, forEachMember, forEachGeneric } = require('../../model/csnUtils');
12
- const { copyAnnotations, getNamespace } = require('../../model/csnUtils');
13
- const { isBetaEnabled } = require('../../base/model.js');
11
+ const { getNamespace, copyAnnotations, cloneCsnNonDict,
12
+ isBuiltinType, isAnnotationExpression,
13
+ forEachDefinition, forEachMember, forEachGeneric } = require('../../model/csnUtils');
14
14
  const { CompilerAssertion } = require('../../base/error');
15
15
 
16
16
  /**
@@ -219,7 +219,16 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
219
219
  }
220
220
  }
221
221
  });
222
- copyAnnotations(typeDef, newType);
222
+
223
+ // expression annos and their sub annotations are not propagated to type
224
+ let [ xprANames, nxprANames ] = Object.keys(typeDef).reduce((acc, pn) => {
225
+ if (pn[0] === '@')
226
+ acc[isAnnotationExpression(typeDef[pn]) ? 0 : 1].push(pn);
227
+ return acc;
228
+ }, [ [], [] ]);
229
+ nxprANames = nxprANames.filter(an => !xprANames.some(ean => an.startsWith(`${ean}.`)));
230
+ copyAnnotations(typeDef, newType, false, {}, nxprANames);
231
+
223
232
  // if the origin type had items, add items to exposed type
224
233
  if(typeDef.kind === 'type') {
225
234
  if(typeDef.items) {
@@ -4,7 +4,6 @@
4
4
  // different backends.
5
5
  // The sibling of model/transform/TransformUtil.js which works with compacted new CSN.
6
6
 
7
- const { makeMessageFunction } = require('../base/messages');
8
7
  const { setProp } = require('../base/model');
9
8
 
10
9
  const { copyAnnotations, applyTransformations, isDollarSelfOrProjectionOperand } = require('../model/csnUtils');
@@ -20,8 +19,8 @@ const RelationalOperators = ['=', '!=', '<>', 'is' /*, 'like'*/,...RestrictedOpe
20
19
  // 'model' is compacted new style CSN
21
20
  // TODO: Error and warnings handling with compacted CSN? - currently just throw new ModelError for everything
22
21
  // TODO: check the situation with assocs with values. In compacted CSN such elements have only "@Core.Computed": true
23
- function getTransformers(model, options, pathDelimiter = '_') {
24
- const { message, error, warning, info } = makeMessageFunction(model, options);
22
+ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
23
+ const { message, error, warning, info } = msgFunctions;
25
24
  const csnUtils = getUtils(model);
26
25
  const {
27
26
  getCsnDef,
@@ -321,48 +320,62 @@ function getTransformers(model, options, pathDelimiter = '_') {
321
320
  * @param {object[]} [links] Pre-resolved links for the given ref - if not provided, will be calculated JIT
322
321
  * @param {string} [scope] Pre-resolved scope for the given ref - if not provided, will be calculated JIT
323
322
  * @param {WeakMap} [resolvedLinkTypes=new WeakMap()] A WeakMap with already resolved types for each link-step - safes an `artifactRef` call
323
+ * @param {bool} [refParentIsItems] relative ref has an items root (suspend flattening by caller)
324
324
  * @returns {string[]}
325
325
  */
326
- function flattenStructStepsInRef(ref, path, links, scope, resolvedLinkTypes=new WeakMap()) {
326
+ function flattenStructStepsInRef(ref, path, links, scope, resolvedLinkTypes=new WeakMap(), refParentIsItems=false) {
327
327
  // Refs of length 1 cannot contain steps - no need to check
328
328
  if (ref.length < 2 || (scope === '$self' && ref.length === 2)) {
329
329
  return ref;
330
330
  }
331
331
 
332
- return flatten(ref, path);
332
+ const result = scope === '$self' ? [ref[0]] : [];
333
+ //let stack = []; // IDs of path steps not yet processed or part of a struct traversal
334
+ if(!links && !scope) { // calculate JIT if not supplied
335
+ const res = inspectRef(path);
336
+ links = res.links;
337
+ scope = res.scope;
338
+ }
339
+ if (scope === '$magic')
340
+ return ref;
333
341
 
334
- function flatten(ref, path) {
335
- let result = scope === '$self' ? [ref[0]] : [];
336
- //let stack = []; // IDs of path steps not yet processed or part of a struct traversal
337
- if(!links && !scope) { // calculate JIT if not supplied
338
- const res = inspectRef(path);
339
- links = res.links;
340
- scope = res.scope;
341
- }
342
- if (scope === '$magic')
343
- return ref;
344
- // Don't process a leading $self - it will a .art with .elements!
345
- const startIndex = scope === '$self' ? 1 : 0;
346
- let flattenStep = false;
347
- for(let i = startIndex; i < links.length; i++) {
348
- const value = links[i];
349
- if (flattenStep) {
350
- result[result.length - 1] += pathDelimiter + (ref[i].id ? ref[i].id : ref[i]);
351
- // if we had a filter or args, we had an assoc so this step is done
352
- // we then keep along the filter/args by updating the id of the current ref
353
- if(ref[i].id) {
354
- ref[i].id = result[result.length-1];
355
- result[result.length-1] = ref[i];
356
- }
357
- }
358
- else {
359
- result.push(ref[i]);
342
+ // Don't process a leading $self - it will a .art with .elements!
343
+ let i = scope === '$self' ? 1 : 0;
344
+
345
+ // read property from resolved path link
346
+ const art = (propName) =>
347
+ (links[i].art?.[propName] ||
348
+ effectiveType(links[i].art)[propName] ||
349
+ (resolvedLinkTypes.get(links[i])||{})[propName]);
350
+
351
+ let flattenStep = false;
352
+ let nextIsItems = !!art('items') || (refParentIsItems && i === 0);
353
+ for(; i < links.length; i++) {
354
+
355
+ if (flattenStep && !nextIsItems) {
356
+ result[result.length - 1] += pathDelimiter + (ref[i].id ? ref[i].id : ref[i]);
357
+ // if we had a filter or args, we had an assoc so this step is done
358
+ // we then keep along the filter/args by updating the id of the current ref
359
+ if(ref[i].id) {
360
+ ref[i].id = result[result.length-1];
361
+ result[result.length-1] = ref[i];
360
362
  }
361
- flattenStep = value.art && !value.art.kind && !value.art.SELECT && !value.art.from && (value.art.elements || effectiveType(value.art).elements || (resolvedLinkTypes.get(value)||{}).elements);
363
+ // suspend flattening if the next path step has some 'items'
364
+ nextIsItems = !!art('items');
362
365
  }
363
-
364
- return result;
366
+ else {
367
+ result.push(ref[i]);
368
+ }
369
+ // revoke items suspension for next assoc step
370
+ if(nextIsItems && art('target'))
371
+ nextIsItems = false;
372
+
373
+ flattenStep = !links[i].art?.kind &&
374
+ !links[i].art?.SELECT &&
375
+ !links[i].art?.from &&
376
+ art('elements');
365
377
  }
378
+ return result;
366
379
  }
367
380
 
368
381
  /**