/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Function) { BoundFunctionPathSegment functionSegment = (BoundFunctionPathSegment)pathSegment; if (FunctionName == functionSegment.FunctionName) { var enumNames = functionSegment.Function.Parameters.Where(p => p.Type.IsEnum()).Select(p => p.Name); if (KeyValuePathSegmentTemplate.TryMatch(ParameterMappings, functionSegment.Values, values, enumNames)) { foreach (KeyValuePair<string, string> nameAndValue in functionSegment.Values) { string name = nameAndValue.Key; object value = functionSegment.GetParameterValue(name); ProcedureRoutingConventionHelpers.AddFunctionParameters(functionSegment.Function, name, value, values, values, ParameterMappings); } return true; } } } return false; }
private static void ValidateCount(ODataPathSegment segment, IEdmModel model) { Contract.Assert(segment != null); Contract.Assert(model != null); NavigationPathSegment navigationPathSegment = segment as NavigationPathSegment; if (navigationPathSegment != null) { if (EdmLibHelpers.IsNotCountable(navigationPathSegment.NavigationProperty, model)) { throw new InvalidOperationException(Error.Format( SRResources.NotCountablePropertyUsedForCount, navigationPathSegment.NavigationPropertyName)); } return; } PropertyAccessPathSegment propertyAccessPathSegment = segment as PropertyAccessPathSegment; if (propertyAccessPathSegment != null) { if (EdmLibHelpers.IsNotCountable(propertyAccessPathSegment.Property, model)) { throw new InvalidOperationException(Error.Format( SRResources.NotCountablePropertyUsedForCount, propertyAccessPathSegment.PropertyName)); } } }
/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.DynamicProperty) { var dynamicPropertyPathSegment = (DynamicPropertyPathSegment)pathSegment; // If we're treating the property name as a parameter store the provided name in our values collection // using the name from the template as the key. if (TreatPropertyNameAsParameterName) { values[PropertyName] = dynamicPropertyPathSegment.PropertyName; values[ODataParameterValue.ParameterValuePrefix + PropertyName] = new ODataParameterValue(dynamicPropertyPathSegment.PropertyName, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string))); return true; } if (PropertyName == dynamicPropertyPathSegment.PropertyName) { return true; } } return false; }
/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Key) { KeyValuePathSegment keySegment = (KeyValuePathSegment)pathSegment; return TryMatch(ParameterMappings, keySegment.Values, values, null); } return false; }
/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Function) { BoundFunctionPathSegment functionSegment = (BoundFunctionPathSegment)pathSegment; if (FunctionName == functionSegment.FunctionName) { return KeyValuePathSegmentTemplate.TryMatch(ParameterMappings, functionSegment.Values, values); } } return false; }
/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.UnboundFunction) { UnboundFunctionPathSegment functionSegment = (UnboundFunctionPathSegment)pathSegment; if (_functionName == functionSegment.FunctionName) { var enumNames = functionSegment.Function.Function.Parameters.Where(p => p.Type.IsEnum()).Select(p => p.Name); return KeyValuePathSegmentTemplate.TryMatch(ParameterMappings, functionSegment.Values, values, enumNames); } } return false; }
private void HandleCountPathSegment(ODataPathSegment segment) { this.IsCountPathSegmentPresent = true; }
private void HandleValuePathSegment(ODataPathSegment segment) { this.IsValuePathSegmentPresent = true; }
private void HandleSingletonPathSegment(ODataPathSegment segment) { var singletonPathSegment = (SingletonPathSegment)segment; var singleton = singletonPathSegment.Singleton; this.currentEntityType = singleton.EntityType(); this.queryable = this.api.Source(singleton.Name, (object[])null); this.currentType = this.queryable.ElementType; }
private void HandleUnboundFunctionPathSegment(ODataPathSegment segment) { var unboundFunctionPathSegment = (UnboundFunctionPathSegment)segment; var functionImport = unboundFunctionPathSegment.Function; var entityTypeRef = functionImport.Function.ReturnType.AsEntity(); this.currentEntityType = entityTypeRef == null ? null : entityTypeRef.EntityDefinition(); object[] queryArgs = null; if (functionImport.Function.Parameters.Any()) { queryArgs = functionImport.Function.Parameters.Select( p => unboundFunctionPathSegment.GetParameterValue(p.Name)).ToArray(); } this.queryable = this.api.Source(functionImport.Name, queryArgs); this.currentType = queryable.ElementType; }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values) { return(pathSegment.SegmentKind == ODataSegmentKinds.Batch); }
private void HandleNavigationPathSegment(ODataPathSegment segment) { var navigationSegment = (NavigationPathSegment)segment; var entityParameterExpression = Expression.Parameter(this.currentType); var navigationPropertyExpression = Expression.Property(entityParameterExpression, navigationSegment.NavigationPropertyName); this.currentEntityType = navigationSegment.NavigationProperty.ToEntityType(); if (navigationSegment.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { // get the element type of the target // (the type should be an EntityCollection<T> for navigation queries). this.currentType = navigationPropertyExpression.Type.GetEnumerableItemType(); // need to explicitly define the delegate type as IEnumerable<T> Type delegateType = typeof(Func<,>).MakeGenericType( queryable.ElementType, typeof(IEnumerable<>).MakeGenericType(this.currentType)); LambdaExpression selectBody = Expression.Lambda(delegateType, navigationPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.SelectMany(this.queryable, selectBody, this.currentType); } else { this.currentType = navigationPropertyExpression.Type; LambdaExpression selectBody = Expression.Lambda(navigationPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.Select(this.queryable, selectBody); } }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values) { return(false); }
private void HandlePropertyAccessPathSegment(ODataPathSegment segment) { var propertySegment = (PropertyAccessPathSegment)segment; var entityParameterExpression = Expression.Parameter(this.currentType); var structuralPropertyExpression = Expression.Property(entityParameterExpression, propertySegment.PropertyName); // Check whether property is null or not before futher selection if (propertySegment.Property.Type.IsNullable) { var whereExpression = CreateNotEqualsNullExpression(structuralPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType); } if (propertySegment.Property.Type.IsCollection()) { // Produces new query like 'queryable.SelectMany(param => param.PropertyName)'. // Suppose 'param.PropertyName' is of type 'IEnumerable<T>', the type of the // resulting query would be 'IEnumerable<T>' too. this.currentType = structuralPropertyExpression.Type.GetEnumerableItemType(); var delegateType = typeof(Func<,>).MakeGenericType( this.queryable.ElementType, typeof(IEnumerable<>).MakeGenericType(this.currentType)); var selectBody = Expression.Lambda(delegateType, structuralPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.SelectMany(this.queryable, selectBody, this.currentType); } else { // Produces new query like 'queryable.Select(param => param.PropertyName)'. this.currentType = structuralPropertyExpression.Type; LambdaExpression selectBody = Expression.Lambda(structuralPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.Select(this.queryable, selectBody); } }
/// <summary> /// Parses the next OData path segment following a complex-typed segment. /// </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 ParseAtComplex(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); } IEdmComplexType previousType = previousEdmType as IEdmComplexType; if (previousType == null) { throw Error.Argument(SRResources.PreviousSegmentMustBeComplexType, previousEdmType); } // look for properties IEdmProperty property = previousType.Properties().SingleOrDefault(p => p.Name == segment); if (property != null) { return new PropertyAccessPathSegment(property); } // Treating as an open property return new UnresolvedPathSegment(segment); }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Singleton) { SingletonPathSegment singletonSegment = (SingletonPathSegment)pathSegment; return singletonSegment.Singleton == Singleton && singletonSegment.SingletonName == SingletonName; } return false; }
/// <summary> /// Parses the next OData path segment following a 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 ParseAtCollection(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 collection = previousEdmType as IEdmCollectionType; if (collection == null) { throw Error.Argument(SRResources.PreviousSegmentMustBeCollectionType, previousEdmType); } switch (collection.ElementType.Definition.TypeKind) { case EdmTypeKind.Entity: return ParseAtEntityCollection(model, previous, previousEdmType, segment, segments); default: throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous)); } }
/// <summary> /// Parses the next OData path segment. /// </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 ParseNextSegment(IEdmModel model, ODataPathSegment previous, IEdmType previousEdmType, string segment, Queue<string> segments) { if (String.IsNullOrEmpty(segment)) { throw Error.Argument(SRResources.SegmentNullOrEmpty); } if (previous == null) { // Parse entry node return ParseEntrySegment(model, segment, segments); } else { // Parse non-entry node if (previousEdmType == null) { throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous)); } switch (previousEdmType.TypeKind) { case EdmTypeKind.Collection: return ParseAtCollection(model, previous, previousEdmType, segment, segments); case EdmTypeKind.Entity: return ParseAtEntity(model, previous, previousEdmType, segment, segments); case EdmTypeKind.Complex: return ParseAtComplex(model, previous, previousEdmType, segment, segments); case EdmTypeKind.Primitive: return ParseAtPrimitiveProperty(model, previous, previousEdmType, segment, segments); case EdmTypeKind.Enum: return ParseAtEnumProperty(model, previous, previousEdmType, segment, segments); default: throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous)); } } }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.ComplexCast) { ComplexCastPathSegment castSegment = (ComplexCastPathSegment)pathSegment; return castSegment.CastType == CastType && castSegment.CastTypeName == CastTypeName; } return false; }
private void HandleKeyValuePathSegment(ODataPathSegment segment) { var keySegment = (KeyValuePathSegment)segment; var parameterExpression = Expression.Parameter(this.currentType, DefaultNameOfParameterExpression); var keyValues = GetPathKeyValues(keySegment, this.currentEntityType); BinaryExpression keyFilter = null; foreach (KeyValuePair<string, object> keyValuePair in keyValues) { var equalsExpression = CreateEqualsExpression(parameterExpression, keyValuePair.Key, keyValuePair.Value); keyFilter = keyFilter == null ? equalsExpression : Expression.And(keyFilter, equalsExpression); } var whereExpression = Expression.Lambda(keyFilter, parameterExpression); this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType); }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Navigation) { NavigationPathSegment navigationSegment = (NavigationPathSegment)pathSegment; return navigationSegment.NavigationProperty == NavigationProperty && navigationSegment.NavigationPropertyName == NavigationPropertyName; } return false; }
private void HandleNavigationPathSegment(ODataPathSegment segment) { var navigationSegment = (NavigationPathSegment)segment; var entityParameterExpression = Expression.Parameter(this.currentType); var navigationPropertyExpression = Expression.Property(entityParameterExpression, navigationSegment.NavigationPropertyName); this.currentEntityType = navigationSegment.NavigationProperty.ToEntityType(); // TODO GitHubIssue#330: EF QueryExecutor will throw exception if check whether collections is null added. // Error message likes "Cannot compare elements of type 'ICollection`1[[EntityType]]'. // Only primitive types, enumeration types and entity types are supported." if (navigationSegment.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { // get the element type of the target // (the type should be an EntityCollection<T> for navigation queries). this.currentType = navigationPropertyExpression.Type.GetEnumerableItemType(); // need to explicitly define the delegate type as IEnumerable<T> Type delegateType = typeof(Func<,>).MakeGenericType( queryable.ElementType, typeof(IEnumerable<>).MakeGenericType(this.currentType)); LambdaExpression selectBody = Expression.Lambda(delegateType, navigationPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.SelectMany(this.queryable, selectBody, this.currentType); } else { // Check whether property is null or not before futher selection var whereExpression = CreateNotEqualsNullExpression(navigationPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType); this.currentType = navigationPropertyExpression.Type; LambdaExpression selectBody = Expression.Lambda(navigationPropertyExpression, entityParameterExpression); this.queryable = ExpressionHelpers.Select(this.queryable, selectBody); } }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Action) { BoundActionPathSegment actionSegment = (BoundActionPathSegment)pathSegment; return actionSegment.Action == Action && actionSegment.ActionName == ActionName; } return false; }
/// <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)); }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.EntitySet) { EntitySetPathSegment entitySetSegment = (EntitySetPathSegment)pathSegment; return entitySetSegment.EntitySet == EntitySet && entitySetSegment.EntitySetName == EntitySetName; } return false; }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.Property) { PropertyAccessPathSegment propertySegment = (PropertyAccessPathSegment)pathSegment; return propertySegment.Property == Property && propertySegment.PropertyName == PropertyName; } return false; }
/// <summary> /// Parses the next OData path segment following a primitive property. /// </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 ParseAtPrimitiveProperty(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 (segment == ODataSegmentKinds.Value) { return new ValuePathSegment(); } throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous)); }
/// <inheritdoc /> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { if (pathSegment.SegmentKind == ODataSegmentKinds.UnboundFunction) { UnboundFunctionPathSegment functionSegment = (UnboundFunctionPathSegment)pathSegment; return functionSegment.Function == Function && functionSegment.FunctionName == FunctionName; } return false; }
/// <summary> /// Parses the next OData path segment following an entity. /// </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 ParseAtEntity(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); } IEdmEntityType previousType = previousEdmType as IEdmEntityType; if (previousType == null) { throw Error.Argument(SRResources.PreviousSegmentMustBeEntityType, previousEdmType); } // first look for navigation properties IEdmNavigationProperty navigation = previousType.NavigationProperties().SingleOrDefault(np => np.Name == segment); if (navigation != null) { return new NavigationPathSegment(navigation); } // next look for properties IEdmProperty property = previousType.Properties().SingleOrDefault(p => p.Name == segment); if (property != null) { return new PropertyAccessPathSegment(property); } // next look for type casts IEdmEntityType castType = model.FindDeclaredType(segment) as IEdmEntityType; if (castType != null) { if (!castType.IsOrInheritsFrom(previousType) && !previousType.IsOrInheritsFrom(castType)) { throw new ODataException(Error.Format(SRResources.InvalidCastInPath, castType, previousType)); } return new CastPathSegment(castType); } // look for $ref if (segment == ODataSegmentKinds.Ref) { return new RefPathSegment(); } // finally look for bindable procedures IEdmAction action = model.FindAction(segment, previousType); if (action != null) { return new BoundActionPathSegment(action); } // Try to match this to a function call BoundFunctionPathSegment pathSegment = TryMatchBoundFunctionCall(segment, segments, model, bindingType: previousType); if (pathSegment != null) { return pathSegment; } // Treating as an open property return new UnresolvedPathSegment(segment); }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { return pathSegment.SegmentKind == ODataSegmentKinds.Batch; }
/// <summary> /// Matches the template with an <see cref="ODataPathSegment"/>. /// </summary> /// <param name="pathSegment">The path segment to match this template with.</param> /// <param name="values">The dictionary of matches to be updated if the segment matches the template.</param> /// <returns><see langword="true"/> if the segment matches the template; otherwise, <see langword="false"/>.</returns> public virtual bool TryMatch(ODataPathSegment pathSegment, IDictionary<string, object> values) { return false; }
private void HandleEntitySetPathSegment(ODataPathSegment segment) { var entitySetPathSegment = (EntitySetPathSegment)segment; var entitySet = entitySetPathSegment.EntitySetBase; this.currentEntityType = entitySet.EntityType(); this.queryable = this.api.Source(entitySet.Name, (object[])null); this.currentType = this.queryable.ElementType; }
/// <inheritdoc/> public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values) { return (pathSegment.SegmentKind == ODataSegmentKinds.DynamicProperty && ((DynamicPropertyPathSegment)pathSegment).PropertyName == PropertyName); }