UNPKG

@sap/xsodata

Version:

Expose data from a HANA database as OData V2 service with help of .xsodata files.

161 lines (148 loc) 5.64 kB
'use strict'; const lodash = require('lodash'); /** * Exports the api */ module.exports = { validate: validate, validateHasNotKeyPropertyToken: validateHasNotKeyPropertyTokenKey, }; /** * Validates the given context containing xsodata configuration with concurrencytokens. * The validation checks all entity types concurrencytokens. * * @param context {object} The context object to validate * @param callback (function) The function called on validation. Expected signature is * callback(err, context) */ function validate(context, callback) { const entityTypes = context.gModel._entityTypesMap; try { validateDefaults(entityTypes); validateHasNotNavigationPropertyTokenKey(entityTypes); validateHasNotKeyPropertyTokenKey(entityTypes); callback(null, context); } catch (err) { callback(err, context); } } /** * Validates that the entity types concurrenytoken does not have an 'empty' property. * * @param {object} entityTypes The entityTypes collection to validate * @throws {Error} When concurrencytoken has an empty property */ function validateDefaults(entityTypes) { findConcurrencyTokenConflicts(entityTypes, null, function (entityType) { if (entityType.getConcurrentPropertiesMap()['']) { throw new Error( "XSODATA configuration has invalid concurrencytoken '' " + 'for entity ' + entityType.name + '. An empty property is not allowed' ); } if (entityType._aggregates && entityType.hasConcurrencyToken()) { throw new Error( 'XSODATA configuration is invalid. Usage of aggregation' + ' and concurrencytoken in same entity definition is not allowed' ); } }); } /** * Validates that the entity types concurrenytoken does not have a property already defined * as a navigation property. * * @param {object} entityTypes The entityTypes collection to validate * @throws {Error} When concurrencytoken property is a navigation property */ function validateHasNotNavigationPropertyTokenKey(entityTypes) { findConcurrencyTokenConflicts( entityTypes, '_entityType.navigates', function (entityType, intersection) { if (intersection.length > 0) { throw new Error( "XSODATA configuration has invalid concurrencytoken '" + intersection.join(',') + "' for entity " + entityType.name + '. A navigation property is not allowed' ); } } ); } /** * Validates that the entity types concurrenytoken does not have a property already defined * as a key or generated key property. * * @param {object} entityTypes The entityTypes collection to validate * @throws {Error} When concurrencytoken property is a key or generated key property */ function validateHasNotKeyPropertyTokenKey(entityTypes) { findConcurrencyTokenConflicts( entityTypes, 'keys.names', function (entityType, intersection) { const isInvalidKey = entityType.hasConcurrentProperties() && entityType.isConcurrentProperty(entityType.keys.generatedKey); if (isInvalidKey) { throw new Error( "XSODATA configuration has invalid concurrencytoken '" + entityType.keys.generatedKey + "' for entity " + entityType.name + '. A key property is not allowed' ); } if (intersection.length > 0) { throw new Error( "XSODATA configuration has invalid concurrencytoken '" + intersection.join(',') + "' for entity " + entityType.name + '. A key property is not allowed' ); } } ); } /** * Iterates over provided entityTypes collection. Returns an intersection between * concurrent properties and properties identified by comparableChildPropertyPath parameter. * * @param entityTypes {object} The collection of entityTypes * @param comparableChildPropertyPath {string} Path to comparable object inside entityTypes object * @param callback {function} Function called on each value found in entityTypes. * Function signature is callback(entityType, intersection) where intersection is an array * of already found key intersections. * @return {array} Intersection of keys of comparables; */ function findConcurrencyTokenConflicts( entityTypes, comparableChildPropertyPath, callback ) { return lodash .chain(entityTypes) .reduce(function (result, entityType) { let comparableKeys; let intersection; let tokenKeys; comparableKeys = lodash .chain(entityType) .get(comparableChildPropertyPath) .value(); if (comparableKeys && !Array.isArray(comparableKeys)) { comparableKeys = lodash.keys(comparableKeys); } tokenKeys = entityType.getConcurrentProperties(); intersection = lodash.intersection(comparableKeys, tokenKeys); callback(entityType, intersection); return result.concat(intersection); }, []) .value(); }