UNPKG

@sap/odata-v4

Version:

OData V4.0 server library

123 lines (108 loc) 4.73 kB
'use strict'; const UriSemanticError = require('../errors/UriSemanticError'); const KeyValueParser = require('./KeyValueParser'); /** * Parsing uri key predicates. * * @extends KeyValueParser */ class KeyPredicateParser extends KeyValueParser { /** * Creates an instance of KeyPredicateParser. * * @param {Edm} edm The Entity Data Model * @param {Object} aliases Alias definitions */ constructor(edm, aliases) { super(edm, aliases); } /** * Parsing the next key predicates. * * @param {UriResource} currentResource The current resource * @param {EdmEntityType} edmEntityType The EdmType of the current resource * @param {UriTokenizer} tokenizer The current uri tokenizer * @returns {UriParameter[]} a map of found parameters */ parse(currentResource, edmEntityType, tokenizer) { const requiredKeyProperties = this._buildRequiredKeyProperties(currentResource, edmEntityType); return [].concat( requiredKeyProperties.size > 1 ? this._parseCompoundKey(requiredKeyProperties, edmEntityType, tokenizer) : this._parseSimpleKey(requiredKeyProperties, edmEntityType, tokenizer) ); } /** * Builds the required key properties map. * * @param {UriResource} currentResource The current resource * @param {EdmEntityType} edmEntityType The edm entity type of current resource * @returns {Map.<string, EdmKeyPropertyRef>} the map of required key properties * @private */ _buildRequiredKeyProperties(currentResource, edmEntityType) { let requiredKeyProperties = new Map(edmEntityType.getKeyPropertyRefs()); const navigationProperty = currentResource.getNavigationProperty(); if (navigationProperty) { const partner = navigationProperty.getPartner(); if (partner) { // "If a navigation property leading to a related entity type has a // partner navigation property that specifies a referential constraint, // then those key properties of the related entity that take part in // the referential constraint MAY be omitted from URLs." for (const name of partner.getReferentialConstraints().keys()) { requiredKeyProperties.delete(name); } } } return requiredKeyProperties; } /** * Parsing a compound key. * * @param {string[]} requiredKeyProperties The required key property names * @param {EdmEntityType} edmEntityType The current edm entity type * @param {UriTokenizer} tokenizer The current tokenizer * @returns {UriParameter[]} The found uri parameters * @private */ _parseCompoundKey(requiredKeyProperties, edmEntityType, tokenizer) { const visitedKeyProperties = super.parse(tokenizer, propertyRefName => edmEntityType.getKeyPropertyRef(propertyRefName), propertyRefType => [propertyRefType.getProperty().getType()] ); // Testing if at least all required key properties have been visited const missingKeyPredicateNames = Array.from(requiredKeyProperties.keys()) .filter(name => !visitedKeyProperties.has(name)); if (missingKeyPredicateNames.length > 0) { throw new UriSemanticError(UriSemanticError.Message.KEY_PREDICATES_MISSING, missingKeyPredicateNames.join(',')); } let result = []; for (let [key, value] of visitedKeyProperties) { result.push(value.setEdmRef(edmEntityType.getKeyPropertyRef(key))); } return result; } /** * Parsing a simple key. * * @param {string[]} requiredKeyProperties The required key property names * @param {EdmEntityType} edmEntityType The current edm entity type * @param {UriTokenizer} tokenizer The current tokenizer * @returns {UriParameter[]} The found uri parameter in an array * @private */ _parseSimpleKey(requiredKeyProperties, edmEntityType, tokenizer) { const propertyRef = requiredKeyProperties.values().next().value; const propertyRefType = propertyRef.getProperty().getType(); // First try to parse key when key is like ES(value) let parameter = this.parseUriParameter(propertyRefType, tokenizer); if (parameter) { return [parameter.setEdmRef(propertyRef)]; } // Second try to parse key when key is like ES(ODataIdentifier=value) return this._parseCompoundKey(requiredKeyProperties, edmEntityType, tokenizer); } } module.exports = KeyPredicateParser;