public static bool IsOrInheritsFrom(this IEdmType thisType, IEdmType otherType)
 {
     if (thisType == null || otherType == null)
     {
         return(false);
     }
     else
     {
         if (!thisType.IsEquivalentTo(otherType))
         {
             EdmTypeKind typeKind = thisType.TypeKind;
             if (typeKind != otherType.TypeKind || typeKind != EdmTypeKind.Entity && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Row)
             {
                 return(false);
             }
             else
             {
                 return(thisType.IsOrInheritsFrom(otherType));
             }
         }
         else
         {
             return(true);
         }
     }
 }
        /// <summary>
        /// Parses the next OData path segment following an entity collection.
        /// </summary>
        /// <param name="model">The model to use for path parsing.</param>
        /// <param name="previous">The previous path segment.</param>
        /// <param name="previousEdmType">The EDM type of the OData path up to the previous segment.</param>
        /// <param name="segment">The value of the segment to parse.</param>
        /// <returns>A parsed representation of the segment.</returns>
        protected virtual ODataPathSegment ParseAtEntityCollection(IEdmModel model, ODataPathSegment previous, IEdmType previousEdmType, string segment)
        {
            if (previous == null)
            {
                throw Error.ArgumentNull("previous");
            }
            if (String.IsNullOrEmpty(segment))
            {
                throw Error.Argument(SRResources.SegmentNullOrEmpty);
            }

            if (previousEdmType == null)
            {
                throw Error.InvalidOperation(SRResources.PreviousSegmentEdmTypeCannotBeNull);
            }
            IEdmCollectionType collectionType = previousEdmType as IEdmCollectionType;

            if (collectionType == null)
            {
                throw Error.Argument(SRResources.PreviousSegmentMustBeEntityCollectionType, previousEdmType);
            }
            IEdmEntityType elementType = collectionType.ElementType.Definition as IEdmEntityType;

            if (elementType == null)
            {
                throw Error.Argument(SRResources.PreviousSegmentMustBeEntityCollectionType, previousEdmType);
            }

            // look for keys first.
            if (segment.StartsWith("(", StringComparison.Ordinal) && segment.EndsWith(")", StringComparison.Ordinal))
            {
                Contract.Assert(segment.Length >= 2);
                string value = segment.Substring(1, segment.Length - 2);
                return(new KeyValuePathSegment(value));
            }

            // next look for casts
            IEdmEntityType castType = model.FindDeclaredType(segment) as IEdmEntityType;

            if (castType != null)
            {
                IEdmType previousElementType = collectionType.ElementType.Definition;
                if (!castType.IsOrInheritsFrom(previousElementType) && !previousElementType.IsOrInheritsFrom(castType))
                {
                    throw new ODataException(Error.Format(SRResources.InvalidCastInPath, castType, previousElementType));
                }
                return(new CastPathSegment(castType));
            }

            // now look for bindable actions
            IEdmEntityContainer container = ExtractEntityContainer(model);
            IEdmFunctionImport  procedure = container.FunctionImports().FindBindableAction(collectionType, segment);

            if (procedure != null)
            {
                return(new ActionPathSegment(procedure));
            }

            throw new ODataException(Error.Format(SRResources.NoActionFoundForCollection, segment, collectionType.ElementType));
        }
Exemple #3
0
        /// <summary>
        /// Check whether the parent and child are properly related types
        /// </summary>
        /// <param name="parentType">the parent type</param>
        /// <param name="childType">the child type</param>
        /// <exception cref="ODataException">Throws if the two types are not related.</exception>
        public static void CheckRelatedTo(IEdmType parentType, IEdmType childType)
        {
            IEdmEntityType childEntityType = childType as IEdmEntityType;

            if (!childEntityType.IsOrInheritsFrom(parentType) && !parentType.IsOrInheritsFrom(childEntityType))
            {
                // If the parentType is an open property, parentType will be null and can't have an ODataFullName.
                string parentTypeName = (parentType != null) ? parentType.ODataFullName() : "<null>";
                throw new ODataException(OData.Strings.MetadataBinder_HierarchyNotFollowed(childEntityType.FullName(), parentTypeName));
            }
        }
        /// <summary>
        /// Throws if the type is not related to the type of the given set.
        /// </summary>
        /// <param name="type">Type to check.</param>
        /// <param name="secondType">Second type, which should be related to the first type.</param>
        /// <param name="segmentName">The segment that is checking this.</param>
        public static void ThrowIfTypesUnrelated(IEdmType type, IEdmType secondType, string segmentName)
        {
            ExceptionUtils.CheckArgumentNotNull(type, "type");
            ExceptionUtils.CheckArgumentNotNull(secondType, "secondType");
            IEdmType           unwrappedType  = type;
            IEdmCollectionType collectionType = type as IEdmCollectionType;

            if (collectionType != null)
            {
                unwrappedType = collectionType.ElementType.Definition;
            }

            if (!unwrappedType.IsOrInheritsFrom(secondType) && !secondType.IsOrInheritsFrom(unwrappedType))
            {
                throw new ODataException(ODataErrorStrings.PathParser_TypeMustBeRelatedToSet(type, secondType, segmentName));
            }
        }
        private static bool TestTypeMatch(this IEdmType expressionType, IEdmType assertedType, EdmLocation location, bool matchExactly, out IEnumerable <EdmError> discoveredErrors)
        {
            if (matchExactly)
            {
                if (!expressionType.IsEquivalentTo(assertedType))
                {
                    discoveredErrors = new EdmError[] { new EdmError(location, EdmErrorCode.ExpressionNotValidForTheAssertedType, Edm.Strings.EdmModel_Validator_Semantic_ExpressionNotValidForTheAssertedType) };
                    return(false);
                }
            }
            else
            {
                // A bad type matches anything (so as to avoid generating spurious errors).
                if (expressionType.TypeKind == EdmTypeKind.None || expressionType.IsBad())
                {
                    discoveredErrors = Enumerable.Empty <EdmError>();
                    return(true);
                }

                if (expressionType.TypeKind == EdmTypeKind.Primitive && assertedType.TypeKind == EdmTypeKind.Primitive)
                {
                    IEdmPrimitiveType primitiveExpressionType = expressionType as IEdmPrimitiveType;
                    IEdmPrimitiveType primitiveAssertedType   = assertedType as IEdmPrimitiveType;
                    if (!primitiveExpressionType.PrimitiveKind.PromotesTo(primitiveAssertedType.PrimitiveKind))
                    {
                        discoveredErrors = new EdmError[] { new EdmError(location, EdmErrorCode.ExpressionPrimitiveKindNotValidForAssertedType, Edm.Strings.EdmModel_Validator_Semantic_ExpressionPrimitiveKindCannotPromoteToAssertedType(expressionType.ToTraceString(), assertedType.ToTraceString())) };
                        return(false);
                    }
                }
                else
                {
                    if (!expressionType.IsOrInheritsFrom(assertedType))
                    {
                        discoveredErrors = new EdmError[] { new EdmError(location, EdmErrorCode.ExpressionNotValidForTheAssertedType, Edm.Strings.EdmModel_Validator_Semantic_ExpressionNotValidForTheAssertedType) };
                        return(false);
                    }
                }
            }

            discoveredErrors = Enumerable.Empty <EdmError>();
            return(true);
        }
Exemple #6
0
        /// <summary>
        /// Try to bind namespace-qualified type cast segment.
        /// </summary>
        internal static bool TryBindTypeCastSegment(string identifier, string parenthesisExpressions, IEdmModel model,
                                                    IList <PathSegment> path,
                                                    PathParserSettings settings)
        {
            if (identifier == null || identifier.IndexOf('.') < 0)
            {
                // type cast should be namespace-qualified name
                return(false);
            }

            PathSegment preSegment = path.LastOrDefault();

            if (preSegment == null)
            {
                // type cast should not be the first segment.
                return(false);
            }

            IEdmSchemaType schemaType = model.ResolveType(identifier, settings.EnableCaseInsensitive);

            if (schemaType == null)
            {
                return(false);
            }

            IEdmType targetEdmType = schemaType as IEdmType;

            if (targetEdmType == null)
            {
                return(false);
            }

            IEdmType previousEdmType = preSegment.EdmType;
            bool     isNullable      = false;

            if (previousEdmType.TypeKind == EdmTypeKind.Collection)
            {
                previousEdmType = ((IEdmCollectionType)previousEdmType).ElementType.Definition;
                isNullable      = ((IEdmCollectionType)previousEdmType).ElementType.IsNullable;
            }

            if (!targetEdmType.IsOrInheritsFrom(previousEdmType) && !previousEdmType.IsOrInheritsFrom(targetEdmType))
            {
                throw new Exception($"Type cast {targetEdmType.FullTypeName()} has no relationship with previous {previousEdmType.FullTypeName()}.");
            }

            // We want the type of the type segment to be a collection if the previous segment was a collection
            IEdmType actualTypeOfTheTypeSegment = targetEdmType;

            if (preSegment.EdmType.TypeKind == EdmTypeKind.Collection)
            {
                var actualEntityTypeOfTheTypeSegment = targetEdmType as IEdmEntityType;
                if (actualEntityTypeOfTheTypeSegment != null)
                {
                    actualTypeOfTheTypeSegment = new EdmCollectionType(new EdmEntityTypeReference(actualEntityTypeOfTheTypeSegment, isNullable));
                }
                else
                {
                    // Complex collection supports type cast too.
                    var actualComplexTypeOfTheTypeSegment = actualTypeOfTheTypeSegment as IEdmComplexType;
                    if (actualComplexTypeOfTheTypeSegment != null)
                    {
                        actualTypeOfTheTypeSegment = new EdmCollectionType(new EdmComplexTypeReference(actualComplexTypeOfTheTypeSegment, isNullable));
                    }
                    else
                    {
                        throw new Exception($"Invalid type cast of {identifier}, it should be entity or complex.");
                    }
                }
            }

            TypeSegment typeCast = new TypeSegment(actualTypeOfTheTypeSegment, preSegment.EdmType, preSegment.NavigationSource, identifier);

            path.Add(typeCast);

            TryBindKeySegment(parenthesisExpressions, path);

            return(true);
        }
 /// <summary>
 /// Check whether the two are properly related types
 /// </summary>
 /// <param name="first">the first type</param>
 /// <param name="second">the second type</param>
 /// <returns>Whether the two types are related.</returns>
 public static bool IsRelatedTo(IEdmType first, IEdmType second)
 {
     return(second.IsOrInheritsFrom(first) || first.IsOrInheritsFrom(second));
 }
        /// <summary>
        /// Parses the next OData path segment following an entity collection.
        /// </summary>
        /// <param name="model">The model to use for path parsing.</param>
        /// <param name="previous">The previous path segment.</param>
        /// <param name="previousEdmType">The EDM type of the OData path up to the previous segment.</param>
        /// <param name="segment">The value of the segment to parse.</param>
        /// <param name="segments">The queue of pending segments.</param>
        /// <returns>A parsed representation of the segment.</returns>
        protected virtual ODataPathSegment ParseAtEntityCollection(IEdmModel model, ODataPathSegment previous,
                                                                   IEdmType previousEdmType, string segment, Queue <string> segments)
        {
            if (previous == null)
            {
                throw Error.ArgumentNull("previous");
            }
            if (segments == null)
            {
                throw Error.ArgumentNull("segments");
            }
            if (String.IsNullOrEmpty(segment))
            {
                throw Error.Argument(SRResources.SegmentNullOrEmpty);
            }

            if (previousEdmType == null)
            {
                throw Error.InvalidOperation(SRResources.PreviousSegmentEdmTypeCannotBeNull);
            }
            IEdmCollectionType collectionType = previousEdmType as IEdmCollectionType;

            if (collectionType == null)
            {
                throw Error.Argument(SRResources.PreviousSegmentMustBeEntityCollectionType, previousEdmType);
            }
            IEdmEntityType elementType = collectionType.ElementType.Definition as IEdmEntityType;

            if (elementType == null)
            {
                throw Error.Argument(SRResources.PreviousSegmentMustBeEntityCollectionType, previousEdmType);
            }

            // look for keys first.
            if (segment.StartsWith("(", StringComparison.Ordinal) && segment.EndsWith(")", StringComparison.Ordinal))
            {
                Contract.Assert(segment.Length >= 2);
                string value = segment.Substring(1, segment.Length - 2);
                return(new KeyValuePathSegment(value));
            }

            // next look for casts
            IEdmEntityType castType = model.FindDeclaredType(segment) as IEdmEntityType;

            if (castType != null)
            {
                IEdmType previousElementType = collectionType.ElementType.Definition;
                if (!castType.IsOrInheritsFrom(previousElementType) && !previousElementType.IsOrInheritsFrom(castType))
                {
                    throw new ODataException(Error.Format(SRResources.InvalidCastInPath, castType, previousElementType));
                }
                return(new CastPathSegment(castType));
            }

            // look for $ref
            if (segment == ODataSegmentKinds.Ref)
            {
                return(new RefPathSegment());
            }

            // now look for bindable actions
            IEdmAction action = model.FindAction(segment, collectionType);

            if (action != null)
            {
                return(new BoundActionPathSegment(action));
            }

            // Try to match this to a function call
            BoundFunctionPathSegment pathSegment = TryMatchBoundFunctionCall(segment, segments, model, bindingType: collectionType);

            if (pathSegment != null)
            {
                return(pathSegment);
            }

            throw new ODataException(Error.Format(SRResources.NoActionFoundForCollection, segment, collectionType.ElementType));
        }
 /// <summary>
 /// Check whether the two are properly related types
 /// </summary>
 /// <param name="first">the first type</param>
 /// <param name="second">the second type</param>
 /// <returns>Whether the two types are related.</returns>
 public static bool IsRelatedTo(IEdmType first, IEdmType second)
 {
     return second.IsOrInheritsFrom(first) || first.IsOrInheritsFrom(second);
 }
Exemple #10
0
 private static bool IsAssignableFrom(IEdmType candidateSupertype, IEdmType candidateSubtype)
 {
     return(candidateSubtype.IsOrInheritsFrom(candidateSupertype));
 }
        private bool TryCreateTypeNameSegment(ODataPathSegment previous, string identifier, string parenthesisExpression, IEdmType targetEdmType)
        {
            if (previous.TargetEdmType == null || targetEdmType == null)
            {
                return false;
            }

            // if the new type segment prevents any results from possibly being returned, then short-circuit and throw a 404.
            IEdmType previousEdmType = previous.TargetEdmType;
            Debug.Assert(previousEdmType != null, "previous.TargetEdmType != null");

            if (previousEdmType.TypeKind == EdmTypeKind.Collection)
            {
                previousEdmType = ((IEdmCollectionType)previousEdmType).ElementType.Definition;
            }

            if (!targetEdmType.IsOrInheritsFrom(previousEdmType) && !previousEdmType.IsOrInheritsFrom(targetEdmType))
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_InvalidTypeIdentifier_UnrelatedType(targetEdmType.ODataFullName(), previousEdmType.ODataFullName()));
            }

            // We want the type of the type segment to be a collection if the previous segment was a collection
            IEdmType actualTypeOfTheTypeSegment = targetEdmType;

            if (previous.EdmType.TypeKind == EdmTypeKind.Collection)
            {
                // creating a new collection type here because the type in the request is just the item type, there is no user-provided collection type.
                var actualEntityTypeOfTheTypeSegment = actualTypeOfTheTypeSegment as IEdmEntityType;
                if (actualEntityTypeOfTheTypeSegment != null)
                {
                    actualTypeOfTheTypeSegment = new EdmCollectionType(new EdmEntityTypeReference(actualEntityTypeOfTheTypeSegment, false));
                }
                else
                {
                    throw new ODataException(Strings.PathParser_TypeCastOnlyAllowedAfterEntityCollection(identifier));
                }
            }

            var typeNameSegment = (ODataPathSegment)new TypeSegment(actualTypeOfTheTypeSegment, previous.TargetEdmNavigationSource)
            {
                Identifier = identifier,
                TargetKind = previous.TargetKind,
                SingleResult = previous.SingleResult,
                TargetEdmType = targetEdmType
            };

            this.parsedSegments.Add(typeNameSegment);

            // Key expressions are allowed on Type segments
            this.TryBindKeyFromParentheses(parenthesisExpression);

            return true;
        }
Exemple #12
0
 private static bool IsAssignableFrom(IEdmType candidateSupertype, IEdmType candidateSubtype)
 {
     return candidateSubtype.IsOrInheritsFrom(candidateSupertype);
 }