UNPKG

@sap/cds-compiler

Version:

CDS (Core Data Services) compiler and backends

82 lines (73 loc) 3.39 kB
'use strict'; 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, };