@sap/cds-compiler
Version:
CDS (Core Data Services) compiler and backends
82 lines (73 loc) • 3.39 kB
JavaScript
;
const { setProp } = require('../../base/model');
const flattening = require('../db/flattening');
const {
applyTransformations, forEachDefinition, forEachMemberRecursively, forEachMember, applyTransformationsOnNonDictionary,
} = require('../../model/csnUtils');
const associations = require('../db/associations');
const backlinks = require('../db/backlinks');
/**
* Turn managed associations into unmanaged ones by
* - unfolding the .keys
* - creating the foreign keys in .elements
* - adding a corresponding on-condition
* @param {CSN.Model} csn Input CSN - will not be transformed
* @param {CSN.Options} options
* @param {object} transformerUtils
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
* @todo Remove .keys afterwards
* @todo Add created foreign keys into .columns in case of a query?
* @returns {CSN.Model}
*/
function turnAssociationsIntoUnmanaged( csn, options, transformerUtils, messageFunctions ) {
const { csnUtils, expandManagedToFksInArray } = transformerUtils;
// TODO: Do we really need this?
forEachDefinition(csn, (artifact, artifactName) => {
setProp(artifact, '$path', [ 'definitions', artifactName ]);
forEachMemberRecursively(artifact, (member, memberName, prop, path) => {
setProp(member, '$path', path);
}, [ 'definitions', artifactName ]);
});
// Flatten out the fks and create the corresponding elements
flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, '_', true, csnUtils, { allowArtifact: () => true, skipDict: {} });
// Add the foreign keys also to the columns if the association itself was explicitly selected
// TODO: Extend the expansion to also expand managed to their foreign
// TODO: Remember where in .elements we had associations and do it then?
applyTransformations(csn, {
columns: expandManagedToFksInArray(),
groupBy: expandManagedToFksInArray(true),
orderBy: expandManagedToFksInArray(true),
}, [], { allowArtifact: artifact => artifact.query !== undefined || artifact.projection !== undefined });
forEachDefinition(csn, associations.getFKAccessFinalizer(csn, options, csnUtils, '_', true));
applyTransformations(csn, {
elements: (_parent, prop, elements, path) => {
forEachMember(_parent, (element, elementName, _prop, elPath) => {
if (element.on) {
applyTransformationsOnNonDictionary(element, 'on', {
ref: (parent, __prop, ref) => {
if (ref[0] === '$self' && ref.length > 1 && !ref[1].startsWith('$')) // TODO: Is this safe?
parent.ref = ref.slice(1);
},
}, {}, elPath);
}
}, path);
},
});
// Calculate the on-conditions from the .keys -
associations.attachOnConditions(csn, csnUtils, '_', { allowArtifact: () => true }, options);
return csn;
}
/**
* Translate $self backlinks to "normal" on-conditions
* @param {CSN.Model} csn Input CSN - will not be transformed
* @param {CSN.Options} options
* @param {object} csnUtils
* @param {object} messageFunctions
*/
function transformBacklinks( csn, options, { csnUtils }, messageFunctions ) {
forEachDefinition(csn, backlinks.getBacklinkTransformer(csnUtils, messageFunctions, options, '_', true));
}
module.exports = {
managedToUnmanaged: turnAssociationsIntoUnmanaged,
transformBacklinks,
};