@sap/cds-compiler
Version:
CDS (Core Data Services) compiler and backends
81 lines (72 loc) • 2.61 kB
JavaScript
;
const { setProp } = require('../base/model');
// Only to be used with validator.js - a correct this value needs to be provided!
/**
* Validate the foreign keys of a managed association
*
* - no usage of array-like fields as foreign keys (also not transitively)
* - no usage of unmanaged association as foreign keys (also not transitively)
*
* @param {object} member Member
* @param {string} memberName Member name
*/
function validateForeignKeys( member, memberName ) {
// We have a managed association
const isManagedAssoc = mem => mem && mem.target && !mem.on;
// Declared as arrow-function to keep scope the same (this value)
const handleAssociation = (mem) => {
for (const key of mem.keys) {
if (key.ref) {
if (!key._art)
continue;
// eslint-disable-next-line no-use-before-define
checkForItemsOrMissingType(key._art, key.ref.join('.'));
}
}
};
// Declared as arrow-function to keep scope the same (this value)
const handleStructured = (mem) => {
for (const elementName of Object.keys(mem.elements)) {
const element = mem.elements[elementName];
// eslint-disable-next-line no-use-before-define
checkForItemsOrMissingType(element, elementName);
}
};
// Recursively perform the checks on an element
// Declared as arrow-function to keep scope the same (this value)
const checkForItemsOrMissingType = (mem, memName) => {
if (mem.items) {
this.error('type-invalid-foreign-key', member.$path, { '#': 'items' });
}
else if (mem.keys) {
handleAssociation(mem);
}
else if (mem.elements) {
handleStructured(mem);
}
else if (mem.type) {
if (mem.type === 'cds.Map') {
this.error('type-invalid-foreign-key', member.$path, { '#': 'std', type: mem.type } );
}
else {
const type = mem.type.ref
? this.artifactRef(mem.type)
: this.csn.definitions[mem.type];
if (type && !type.$visited) {
setProp(type, '$visited', true);
checkForItemsOrMissingType(type, memName);
delete type.$visited;
}
}
}
else if (mem && !mem.type && this.options.transformation !== 'odata') {
const variant = member.type === 'cds.Composition' ? 'managedCompForeignKey' : 'managedAssocForeignKey';
this.error('check-proper-type-of', member.$path, {
'#': variant, name: memName, art: memberName,
});
}
};
if (isManagedAssoc(member))
checkForItemsOrMissingType(member, memberName);
}
module.exports = validateForeignKeys;