/// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as positional values. E.g. EntitySet('key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="positionalValues">The list of positional values.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable <KeyValuePair <string, object> > ResolveKeys(IEdmEntityType type, IList <string> positionalValues, Func <IEdmTypeReference, string, object> convertFunc)
        {
            var keyProperties = type.Key().ToList();

            // Throw an error if key size from url doesn't match that from model.
            // Other derived ODataUriResolver intended for alternative key resolution, such as the built in AlternateKeysODataUriResolver,
            // should override this ResolveKeys method.
            if (keyProperties.Count != positionalValues.Count)
            {
                throw ExceptionUtil.CreateBadRequestError(Strings.BadRequest_KeyCountMismatch(type.FullName()));
            }

            var keyPairList = new List <KeyValuePair <string, object> >(positionalValues.Count);

            for (int i = 0; i < keyProperties.Count; i++)
            {
                string       valueText      = positionalValues[i];
                IEdmProperty keyProperty    = keyProperties[i];
                object       convertedValue = convertFunc(keyProperty.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                keyPairList.Add(new KeyValuePair <string, object>(keyProperty.Name, convertedValue));
            }

            return(keyPairList);
        }
Esempio n. 2
0
        /// <summary>Tries to create a key segment for the given filter if it is non empty.</summary>
        /// <param name="previous">Segment on which to compose.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="parenthesisExpression">Parenthesis expression of segment.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <param name="keySegment">The key segment that was created if the key was non-empty.</param>
        /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param>
        /// <returns>Whether the key was non-empty.</returns>
        internal static bool TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, string parenthesisExpression, ODataUriResolver resolver, out ODataPathSegment keySegment, bool enableUriTemplateParsing = false)
        {
            Debug.Assert(parenthesisExpression != null, "parenthesisExpression != null");
            Debug.Assert(previous != null, "segment!= null");
            Debug.Assert(resolver != null, "resolver != null");

            if (previous.SingleResult)
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            SegmentArgumentParser key;

            if (!SegmentArgumentParser.TryParseKeysFromUri(parenthesisExpression, out key, enableUriTemplateParsing))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            // People/NS.Employees() is OK, just like People() is OK
            if (key.IsEmpty)
            {
                keySegment = null;
                return(false);
            }

            keySegment = CreateKeySegment(previous, previousKeySegment, key, resolver);
            return(true);
        }
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as name value pairs. E.g. EntitySet(ID='key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="namedValues">The dictionary of name value pairs.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable <KeyValuePair <string, object> > ResolveKeys(IEdmEntityType type, IDictionary <string, string> namedValues, Func <IEdmTypeReference, string, object> convertFunc)
        {
            var convertedPairs = new Dictionary <string, object>(StringComparer.Ordinal);
            var keyProperties  = type.Key().ToList();

            // Throw an error if key size from url doesn't match that from model.
            // Other derived ODataUriResolver intended for alternative key resolution, such as the built in AlternateKeysODataUriResolver,
            // should override this ResolveKeys method.
            if (keyProperties.Count != namedValues.Count)
            {
                throw ExceptionUtil.CreateBadRequestError(Strings.BadRequest_KeyCountMismatch(type.FullName()));
            }

            foreach (IEdmStructuralProperty property in keyProperties)
            {
                string valueText;

                if (!namedValues.TryGetValue(property.Name, out valueText))
                {
                    if (EnableCaseInsensitive)
                    {
                        var list = namedValues.Keys.Where(key => string.Equals(property.Name, key, StringComparison.OrdinalIgnoreCase)).ToList();
                        if (list.Count > 1)
                        {
                            throw new ODataException(Strings.UriParserMetadata_MultipleMatchingKeysFound(property.Name));
                        }
                        else if (list.Count == 0)
                        {
                            throw ExceptionUtil.CreateSyntaxError();
                        }

                        valueText = namedValues[list.Single()];
                    }
                    else
                    {
                        throw ExceptionUtil.CreateSyntaxError();
                    }
                }

                object convertedValue = convertFunc(property.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                convertedPairs[property.Name] = convertedValue;
            }

            return(convertedPairs);
        }
Esempio n. 4
0
        /// <summary>
        /// Parses the key properties based on the segment's target type, then creates a new segment for the key.
        /// </summary>
        /// <param name="segment">The segment to apply the key to.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="key">The key to apply.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>The newly created key segment.</returns>
        private static KeySegment CreateKeySegment(ODataPathSegment segment, KeySegment previousKeySegment, SegmentArgumentParser key, ODataUriResolver resolver)
        {
            Debug.Assert(segment != null, "segment != null");
            Debug.Assert(key != null && !key.IsEmpty, "key != null && !key.IsEmpty");
            Debug.Assert(segment.SingleResult == false, "segment.SingleResult == false");

            IEdmEntityType targetEntityType = null;

            if (!(segment.TargetEdmType != null && segment.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType)))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            Debug.Assert(targetEntityType != null, "targetEntityType != null");

            // Make sure the keys specified in the uri matches with the number of keys in the metadata
            var keyProperties = targetEntityType.Key().ToList();

            if (keyProperties.Count != key.ValueCount)
            {
                NavigationPropertySegment currentNavPropSegment = segment as NavigationPropertySegment;
                if (currentNavPropSegment != null)
                {
                    key = KeyFinder.FindAndUseKeysFromRelatedSegment(key, keyProperties, currentNavPropSegment.NavigationProperty, previousKeySegment);
                }

                // if we still didn't find any keys, then throw an error.
                if (keyProperties.Count != key.ValueCount && resolver.GetType() == typeof(ODataUriResolver))
                {
                    throw ExceptionUtil.CreateBadRequestError(ErrorStrings.BadRequest_KeyCountMismatch(targetEntityType.FullName()));
                }
            }

            if (!key.AreValuesNamed && key.ValueCount > 1 && resolver.GetType() == typeof(ODataUriResolver))
            {
                throw ExceptionUtil.CreateBadRequestError(ErrorStrings.RequestUriProcessor_KeysMustBeNamed);
            }

            IEnumerable <KeyValuePair <string, object> > keyPairs;

            if (!key.TryConvertValues(targetEntityType, out keyPairs, resolver))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            return(new KeySegment(segment, keyPairs, targetEntityType, segment.TargetEdmNavigationSource));
        }
Esempio n. 5
0
        /// <summary>
        /// Gets the target entity set for the given operation import.
        /// </summary>
        /// <param name="operationImport">The operation import.</param>
        /// <param name="sourceEntitySet">The source entity set.</param>
        /// <param name="model">The model.</param>
        /// <returns>The target entity set of the operation import or null if it could not be determined.</returns>
        internal static IEdmEntitySetBase GetTargetEntitySet(this IEdmOperationImport operationImport, IEdmEntitySetBase sourceEntitySet, IEdmModel model)
        {
            IEdmEntitySetBase targetEntitySet;

            if (operationImport.TryGetStaticEntitySet(model, out targetEntitySet))
            {
                return(targetEntitySet);
            }

            if (sourceEntitySet == null)
            {
                return(null);
            }

            if (operationImport.Operation.IsBound && operationImport.Operation.Parameters.Any())
            {
                IEdmOperationParameter parameter;
                Dictionary <IEdmNavigationProperty, IEdmPathExpression> path;
                IEnumerable <EdmError> errors;

                if (operationImport.TryGetRelativeEntitySetPath(model, out parameter, out path, out errors))
                {
                    IEdmEntitySetBase currentEntitySet = sourceEntitySet;

                    foreach (var navigation in path)
                    {
                        currentEntitySet = currentEntitySet.FindNavigationTarget(navigation.Key, navigation.Value) as IEdmEntitySetBase;
                        if (currentEntitySet is IEdmUnknownEntitySet)
                        {
                            return(currentEntitySet);
                        }
                    }

                    return(currentEntitySet);
                }
                else
                {
                    if (errors.Any(
                            e => e.ErrorCode == EdmErrorCode.InvalidPathFirstPathParameterNotMatchingFirstParameterName))
                    {
                        throw ExceptionUtil.CreateSyntaxError();
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as name value pairs. E.g. EntitySet(ID='key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="namedValues">The dictionary of name value pairs.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable <KeyValuePair <string, object> > ResolveKeys(IEdmEntityType type, IDictionary <string, string> namedValues, Func <IEdmTypeReference, string, object> convertFunc)
        {
            var convertedPairs = new Dictionary <string, object>(StringComparer.Ordinal);
            var keyProperties  = type.Key().ToList();

            foreach (IEdmStructuralProperty property in keyProperties)
            {
                string valueText;

                if (!namedValues.TryGetValue(property.Name, out valueText))
                {
                    if (EnableCaseInsensitive)
                    {
                        var list = namedValues.Keys.Where(key => string.Equals(property.Name, key, StringComparison.OrdinalIgnoreCase)).ToList();
                        if (list.Count > 1)
                        {
                            throw new ODataException(Strings.UriParserMetadata_MultipleMatchingKeysFound(property.Name));
                        }
                        else if (list.Count == 0)
                        {
                            throw ExceptionUtil.CreateSyntaxError();
                        }

                        valueText = namedValues[list.Single()];
                    }
                    else
                    {
                        throw ExceptionUtil.CreateSyntaxError();
                    }
                }

                object convertedValue = convertFunc(property.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                convertedPairs[property.Name] = convertedValue;
            }

            return(convertedPairs);
        }
Esempio n. 7
0
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as positional values. E.g. EntitySet('key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="positionalValues">The list of positional values.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable <KeyValuePair <string, object> > ResolveKeys(IEdmEntityType type, IList <string> positionalValues, Func <IEdmTypeReference, string, object> convertFunc)
        {
            var keyProperties = type.Key().ToList();
            var keyPairList   = new List <KeyValuePair <string, object> >(positionalValues.Count);

            for (int i = 0; i < keyProperties.Count; i++)
            {
                string       valueText      = positionalValues[i];
                IEdmProperty keyProperty    = keyProperties[i];
                object       convertedValue = convertFunc(keyProperty.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                keyPairList.Add(new KeyValuePair <string, object>(keyProperty.Name, convertedValue));
            }

            return(keyPairList);
        }
Esempio n. 8
0
        /// <summary>
        /// Gets the target entity set for the given operation import.
        /// </summary>
        /// <param name="operation">The operation.</param>
        /// <param name="source">The source of operation.</param>
        /// <param name="model">The model.</param>
        /// <returns>The target entity set of the operation import or null if it could not be determined.</returns>
        internal static IEdmEntitySetBase GetTargetEntitySet(this IEdmOperation operation, IEdmNavigationSource source, IEdmModel model)
        {
            if (source == null)
            {
                return(null);
            }

            if (operation.IsBound && operation.Parameters.Any())
            {
                IEdmOperationParameter parameter;
                Dictionary <IEdmNavigationProperty, IEdmPathExpression> path;
                IEdmEntityType         lastEntityType;
                IEnumerable <EdmError> errors;

                if (operation.TryGetRelativeEntitySetPath(model, out parameter, out path, out lastEntityType, out errors))
                {
                    IEdmNavigationSource target = source;

                    foreach (var navigation in path)
                    {
                        target = target.FindNavigationTarget(navigation.Key, navigation.Value);
                    }

                    return(target as IEdmEntitySetBase);
                }
                else
                {
                    if (errors.Any(
                            e => e.ErrorCode == EdmErrorCode.InvalidPathFirstPathParameterNotMatchingFirstParameterName))
                    {
                        throw ExceptionUtil.CreateSyntaxError();
                    }
                }
            }

            return(null);
        }