@sap/cds-compiler 4.9.4 → 4.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@
7
7
  Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
+ ## Version 4.9.6 - 2024-07-15
11
+
12
+ ### Fixed
13
+
14
+ - for.seal: Don't generate DRAFT artifacts.
15
+ - for.odata: Propagate all `@odata { Type, MaxLength, Precision, Scale, SRID }` to generated foreign keys.
16
+ - to.edm(x): Respect `AppliesTo` specification in term definitions for actions and functions.
17
+ - to.sql: Conditions inside filters in combination with foreign key aliases were not properly translated in rare cases.
18
+
10
19
  ## Version 4.9.4 - 2024-05-21
11
20
 
12
21
  ### Fixed
@@ -261,6 +261,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
261
261
  const entityName = nameParts.pop();
262
262
 
263
263
  Object.entries(cObject.actions).forEach(([ n, action ]) => {
264
+ setProp(action, '$isBound', true);
264
265
  const actionName = `${serviceName}.${isV2() ? `${entityName}_` : ''}${n}`;
265
266
  handleAction(actionName, action, cObjectname, [ ...location, 'actions', n ]);
266
267
  });
@@ -516,13 +517,14 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
516
517
  if (carrier.kind === 'entity') {
517
518
  // If AppliesTo=[EntitySet/Singleton/Collection, EntityType], EntitySet/Singleton/Collection has precedence
518
519
  testToAlternativeEdmTargetP = ((x) => {
519
- if (options.isV2())
520
- return [ 'Singleton', 'EntitySet', 'Collection' ].some(y => x.includes(y));
521
-
522
-
523
- return edmUtils.isSingleton(carrier)
524
- ? x.includes('Singleton')
525
- : [ 'EntitySet', 'Collection' ].some(y => x.includes(y));
520
+ if (x) {
521
+ if (options.isV2())
522
+ return [ 'Singleton', 'EntitySet', 'Collection' ].some(y => x.includes(y));
523
+ return edmUtils.isSingleton(carrier)
524
+ ? x.includes('Singleton')
525
+ : [ 'EntitySet', 'Collection' ].some(y => x.includes(y));
526
+ }
527
+ return true;
526
528
  });
527
529
  testToStandardEdmTargetP = (x => (x ? x.includes('EntityType') : true));
528
530
  // if carrier has an alternate 'entitySetName' use this instead of EdmTargetName
@@ -540,6 +542,23 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
540
542
  else if (carrier.kind === 'type') {
541
543
  testToStandardEdmTargetP = (x => (x ? x.includes(carrier.elements ? 'ComplexType' : 'TypeDefinition') : true));
542
544
  }
545
+ else if (carrier.kind === 'action' || carrier.kind === 'function') {
546
+ const type = carrier.kind === 'action' ? 'Action' : 'Function';
547
+ const container = carrier.kind === 'action' ? 'ActionImport' : 'FunctionImport';
548
+ if (options.isV4()) {
549
+ testToStandardEdmTargetP = (x => (x ? x.includes(type) : true));
550
+ // Unbound actions/functions are Action/FunctionImports and are bound to container target
551
+ testToAlternativeEdmTargetP = (x => (x ? x.includes(container) && !carrier.$isBound : true));
552
+ const lastDotIndex = carrier.name.lastIndexOf('.');
553
+ alternativeEdmTargetNameP = lastDotIndex > -1
554
+ ? `${serviceName}.EntityContainer/${carrier.name.substring(lastDotIndex + 1)}`
555
+ : `${serviceName}.EntityContainer/${carrier.name}`;
556
+ hasAlternativeCarrierP = true;
557
+ }
558
+ if (options.isV2())
559
+ // same as in V4 but everything goes to standard target
560
+ testToStandardEdmTargetP = (x => (x ? x.includes(type) || (x.includes(container) && !carrier.$isBound) : true));
561
+ }
543
562
  else if (carrier.kind === 'service') {
544
563
  // if annotated object is a service, annotation goes to EntityContainer,
545
564
  // except if AppliesTo contains Schema but not EntityContainer, then annotation goes to Schema
@@ -16,6 +16,7 @@ const { setProp, isBetaEnabled } = require('../../base/model');
16
16
  const { forEach } = require('../../utils/objectUtils');
17
17
  const { transformExpression } = require('./applyTransformations');
18
18
  const { cloneCsnNonDict } = require('../../model/cloneCsn');
19
+ const { EdmTypeFacetNames } = require('../../edm/EdmPrimitiveTypeDefinitions');
19
20
 
20
21
  /**
21
22
  * Strip off leading $self from refs where applicable.
@@ -828,11 +829,11 @@ function createForeignKeys( csnUtils, path, element, prefix, csn, options, pathD
828
829
  else if (finalElement.type == null || isBuiltinType(finalElement.type)) {
829
830
  const newFk = Object.create(null);
830
831
  setProp(newFk, '$extensionPath', extensionPath);
831
- for (const prop of [ 'type', 'length', 'scale', 'precision', 'srid', 'default', '@odata.Type' ]) {
832
+ [ 'type', 'length', 'scale', 'precision', 'srid', 'default', '@odata.Type', ...EdmTypeFacetNames.map(f => `@odata.${f}`) ].forEach((prop) => {
832
833
  // copy props from original element to preserve derived types!
833
834
  if (element[prop] !== undefined)
834
835
  newFk[prop] = element[prop];
835
- }
836
+ });
836
837
  return [ [ prefix, newFk ] ];
837
838
  }
838
839
 
@@ -11,7 +11,6 @@ const validate = require('../../checks/validator');
11
11
  const expansion = require('../db/expansion');
12
12
  const queries = require('./queries');
13
13
  const associations = require('./associations');
14
- const generateDrafts = require('../draft/db');
15
14
  const handleExists = require('../db/transformExists');
16
15
  const misc = require('./misc');
17
16
  const annotations = require('./annotations');
@@ -77,7 +76,6 @@ function effectiveCsn( model, options, messageFunctions ) {
77
76
  processCalculatedElementsInEntities(csn);
78
77
  associations.managedToUnmanaged(csn, options, csnUtils, messageFunctions);
79
78
  associations.transformBacklinks(csn, options, csnUtils, messageFunctions);
80
- generateDrafts(csn, options, '_', messageFunctions);
81
79
  const transformers = mergeTransformers([ misc.attachPersistenceName(csn, options, csnUtils), options.remapOdataAnnotations ? annotations.remapODataAnnotations(csn) : {}, misc.removeDefinitionsAndProperties(csn, options) ], null);
82
80
  applyTransformations(csn, transformers, [], { skipIgnore: false });
83
81
 
@@ -1110,8 +1110,27 @@ function translateAssocsToJoins(model, inputOptions = {})
1110
1110
  }
1111
1111
  else {
1112
1112
  const [ tableAlias, path ] = getTableAliasAndPathSteps(pathNode);
1113
- const pathStr = path.map(ps => ps.id).join(pathDelimiter);
1114
- replaceNodeContent(pathNode, constructPathNode([ tableAlias, { id: pathStr, _artifact: pathNode._artifact } ]));
1113
+ const rewrittenPath = [];
1114
+ const leafArtifact = path.at(-1)._artifact;
1115
+ // Walk from left to right and search for first assoc. If assocs in filters become join relevant in the future,
1116
+ // i.e. not only fk-access, we need to revisit this
1117
+ for(let i = 0; i < path.length; i++) {
1118
+ const pathStep = path[i];
1119
+ if(pathStep._artifact?.foreignKeys) {
1120
+ const possibleNonAliasedFkName = path.slice(i).map(ps => ps.id).join(pathDelimiter);
1121
+ if(!pathStep._artifact.$flatSrcFKs)
1122
+ setProp(pathStep._artifact, '$flatSrcFKs', flattenElement(pathStep._artifact, true, pathStep._artifact.name.id, pathStep._artifact.name.id));
1123
+ const fk = pathStep._artifact.$flatSrcFKs.find(f => f._artifact === leafArtifact && f.acc.startsWith(possibleNonAliasedFkName));
1124
+ if(fk) {
1125
+ rewrittenPath.push(fk);
1126
+ i = path.length;
1127
+ continue;
1128
+ }
1129
+ }
1130
+
1131
+ rewrittenPath.push(pathStep);
1132
+ }
1133
+ replaceNodeContent(pathNode, constructPathNode([ tableAlias, { id: rewrittenPath.map(ps => ps.id).join(pathDelimiter), _artifact: pathNode._artifact } ]));
1115
1134
  }
1116
1135
  }
1117
1136
  } ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "4.9.4",
3
+ "version": "4.9.6",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",