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)); }
/// <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); }
/// <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); }
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; }
private static bool IsAssignableFrom(IEdmType candidateSupertype, IEdmType candidateSubtype) { return candidateSubtype.IsOrInheritsFrom(candidateSupertype); }