UNPKG

@sap/xsodata

Version:

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

138 lines (114 loc) 5.07 kB
'use strict'; var 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) { var 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) { var 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) { var comparableKeys; var intersection; var 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(); }