/// <inheritdoc/> public Expression Expand(QueryExpressionContext context) { Ensure.NotNull(context, "context"); var result = CallInner(context); if (result != null) { return(result); } // Ensure this query constructs from DataSourceStub. if (context.ModelReference is DataSourceStubModelReference) { // Only expand entity set query which returns IQueryable<T>. var query = ModelCache.GetEntitySetQuery(context); if (query != null) { return(query.Expression); } } // No expansion happened just return the node itself. return(context.VisitedNode); }
/// <inheritdoc/> public Expression Expand(QueryExpressionContext context) { IQueryable result = GetEntitySetQuery(context); if (result != null) { // Only Expand to expression of method call on ApiData class var methodCall = result.Expression as MethodCallExpression; if (methodCall != null) { var method = methodCall.Method; if (method.DeclaringType == typeof(ApiData) && method.Name != "Value") { return(null); } else { return(result.Expression); } } return(null); } return(null); }
/// <inheritdoc/> public Expression Filter(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (context.ModelReference == null) { return(null); } var apiDataReference = context.ModelReference as ApiDataReference; if (apiDataReference == null) { return(null); } var entitySet = apiDataReference.Element as IEdmEntitySet; if (entitySet == null) { return(null); } var returnType = context.VisitedNode.Type .FindGenericType(typeof(IQueryable <>)); var elementType = returnType.GetGenericArguments()[0]; var methodName = ConventionBasedChangeSetConstants.FilterMethodEntitySetFilter + entitySet.Name; var method = this.targetType.GetQualifiedMethod(methodName); if (method != null && method.IsFamily && method.ReturnType == returnType) { object target = null; if (!method.IsStatic) { target = context.QueryContext.ApiContext.GetProperty( typeof(Api).AssemblyQualifiedName); if (target == null || !this.targetType.IsAssignableFrom(target.GetType())) { return(null); } } var parameters = method.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == returnType) { var queryType = typeof(EnumerableQuery <>) .MakeGenericType(elementType); var query = Activator.CreateInstance(queryType, context.VisitedNode); var result = method.Invoke(target, new object[] { query }) as IQueryable; if (result != null && result != query) { return(result.Expression); } } } return(null); }
/// <inheritdoc/> public Expression Filter(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (Inner != null) { var innerFilteredExpression = Inner.Filter(context); if (innerFilteredExpression != null && innerFilteredExpression != context.VisitedNode) { return(innerFilteredExpression); } } // 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 (context.VisitedNode.NodeType == ExpressionType.NotEqual) { var binaryExp = (BinaryExpression)context.VisitedNode; var left = binaryExp.Left as MemberExpression; var right = binaryExp.Right as ConstantExpression; bool leftCheck = left != null && left.Type.IsGenericType && left.Type.GetGenericTypeDefinition() == typeof(ICollection <>); bool rightCheck = right != null && right.Value == null; if (leftCheck && rightCheck) { return(Expression.Constant(true)); } } return(context.VisitedNode); }
/// <summary> /// Expands an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <returns> /// An expanded expression of the same type as the visited node, or /// if expansion did not apply, the visited node or <c>null</c>. /// </returns> public Expression Expand(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (this.InnerHandler != null) { var result = this.InnerHandler.Expand(context); if (result != null) { return(result); } } if (context.ModelReference == null) { return(null); } var apiDataReference = context.ModelReference as ApiDataReference; if (apiDataReference == null) { return(null); } var entitySet = apiDataReference.Element as IEdmEntitySet; if (entitySet == null) { return(null); } var target = context.QueryContext.ApiContext.GetProperty( typeof(Api).AssemblyQualifiedName); var entitySetProperty = target.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .SingleOrDefault(p => p.Name == entitySet.Name); if (entitySetProperty != null) { var policies = entitySetProperty.GetCustomAttributes() .OfType <IApiPolicy>(); foreach (var policy in policies) { policy.Activate(context.QueryContext); } context.AfterNestedVisitCallback = () => { foreach (var policy in policies.Reverse()) { policy.Deactivate(context.QueryContext); } }; } return(context.VisitedNode); }
/// <summary> Sources an expression. </summary> /// /// <param name="context"> The query expression context. </param> /// <param name="embedded"> Indicates if the sourcing is occurring on an embedded node. </param> /// /// <returns> A data source expression that represents the visited node. </returns> public System.Linq.Expressions.Expression Source(QueryExpressionContext context, bool embedded) { //Source query expression dynamically var dbContext = context.QueryContext.ApiContext.GetProperty <DynamicContext>(DynamicContext.cDbContextKey); if (dbContext != null) { string name = context.ModelReference.EntitySet.Name; Type type = dbContext.GetModelType(name); if (type != null) { var dbSet = dbContext.Set(type); return(Expression.Constant(dbSet)); } } if (this.InnerHandler != null) { return(this.InnerHandler.Source(context, embedded)); } else { throw new NotImplementedException(); } }
/// <inheritdoc/> public Expression Process(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (Inner != null) { var innerFilteredExpression = Inner.Process(context); if (innerFilteredExpression != null && innerFilteredExpression != context.VisitedNode) { return(innerFilteredExpression); } } // TODO GitHubIssue#330: EF QueryExecutor will throw exception if check whether collections is null added. // Exception message likes "Cannot compare elements of type 'ICollection`1[[EntityType]]'. // Only primitive types, enumeration types and entity types are supported." // EF does not support complex != null neither, and it requires complex not null. // EF model builder set complex type not null by default, but Web Api OData does not. if (context.VisitedNode.NodeType == ExpressionType.NotEqual) { var binaryExp = (BinaryExpression)context.VisitedNode; var left = binaryExp.Left as MemberExpression; var right = binaryExp.Right as ConstantExpression; bool rightCheck = right != null && right.Value == null; // Check right first which is simple if (!rightCheck) { return(context.VisitedNode); } bool leftCheck = false; if (left != null) { // If it is a collection, then replace coll != null with true leftCheck = left.Type.IsGenericType && left.Type.GetGenericTypeDefinition() == typeof(ICollection <>); // If it is a complex, replace complex!=null with true if (!leftCheck) { var modelRef = context.GetModelReferenceForNode(left); if (modelRef != null && modelRef.Type != null) { leftCheck = modelRef.Type.TypeKind.Equals(EdmTypeKind.Complex); } } } if (leftCheck) { return(Expression.Constant(true)); } } return(context.VisitedNode); }
private Expression CallInner(QueryExpressionContext context) { if (this.InnerHandler != null) { return(this.InnerHandler.Expand(context)); } return(null); }
private Expression CallInner(QueryExpressionContext context, bool embedded) { if (this.InnerHandler != null) { return(this.InnerHandler.ReplaceQueryableSource(context, embedded)); } return(null); }
public static SelectQueryInfo VisitQueryExpression(QueryExpressionContext context) { if (context.queryExpression() != null) { return(VisitQueryExpression(context.queryExpression())); } return(VisitQuerySpecification(context.querySpecification())); }
public static QsiTableNode VisitQueryExpression(QueryExpressionContext context) { if (context.querySpecification() != null) { return(VisitQuerySpecification(context.querySpecification())); } return(VisitQueryExpression(context.queryExpression())); }
/// <summary> Expands an expression. </summary> /// /// <param name="context"> The query expression context. </param> /// /// <returns> /// An expanded expression of the same type as the visited node, or if expansion did not apply, /// the visited node or <c>null</c>. /// </returns> public System.Linq.Expressions.Expression Expand(QueryExpressionContext context) { //TODO: Expand query expression dynamically if (this.InnerHandler != null) { return(this.InnerHandler.Expand(context)); } else { throw new NotImplementedException(); } }
/// <summary> /// Expands an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <returns> /// An expanded expression of the same type as the visited node, or /// if expansion did not apply, the visited node or <c>null</c>. /// </returns> public Expression Expand(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (context.ModelReference == null) { return(CallInner(context)); } var dataSourceStubReference = context.ModelReference as DataSourceStubReference; if (dataSourceStubReference == null) { return(CallInner(context)); } var entitySet = dataSourceStubReference.Element as IEdmEntitySet; if (entitySet == null) { return(CallInner(context)); } var target = context.QueryContext.GetApiService <ApiBase>(); var entitySetProperty = target.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .SingleOrDefault(p => p.Name == entitySet.Name); if (entitySetProperty != null) { var policies = entitySetProperty.GetCustomAttributes() .OfType <IApiPolicy>(); foreach (var policy in policies) { policy.Activate(context.QueryContext); } context.AfterNestedVisitCallback = () => { foreach (var policy in policies.Reverse()) { policy.Deactivate(context.QueryContext); } }; } // This class is used to activate and deactivate the policies // thus it is NOT intended to actually expand any query here. return(CallInner(context)); }
/// <summary> /// Inspects an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <returns> /// <c>true</c> if the inspection passed; otherwise, <c>false</c>. /// </returns> public bool Inspect(QueryExpressionContext context) { Ensure.NotNull(context, "context"); // TODO GitHubIssue#35 : Support Inspect more elements in authorization if (context.ModelReference == null) { return(true); } var apiDataReference = context.ModelReference as ApiDataReference; if (apiDataReference == null) { return(true); } var entitySet = apiDataReference.Element as IEdmEntitySet; if (entitySet == null) { return(true); } var assertedRoles = context.QueryContext .GetProperty <List <string> >(AssertedRoles); var permissions = context.QueryContext.ApiContext.Configuration .GetProperty <IEnumerable <ApiPermission> >(Permissions); if (permissions == null) { throw new SecurityException( string.Format(CultureInfo.InvariantCulture, Resources.ReadDeniedOnEntitySet, entitySet.Name)); } permissions = permissions.Where(p => ( p.PermissionType == ApiPermissionType.All || p.PermissionType == ApiPermissionType.Read) && ( (p.NamespaceName == null && p.SecurableName == null) || (p.NamespaceName == null && p.SecurableName == entitySet.Name)) && p.ChildName == null && (p.Role == null || this.IsInRole(p.Role) || (assertedRoles != null && assertedRoles.Contains(p.Role)))); if (!permissions.Any() || permissions.Any(p => p.IsDeny)) { throw new SecurityException( string.Format(CultureInfo.InvariantCulture, Resources.ReadDeniedOnEntitySet, entitySet.Name)); } return(true); }
/// <summary> /// Initializes a new instance of the <see cref="QueryExpressionContextTests"/> class. /// </summary> public QueryExpressionContextTests() { serviceProviderFixture = new ServiceProviderMock(); var api = new TestApi(serviceProviderFixture.ServiceProvider.Object); var queryableSource = new QueryableSource <Test>(Expression.Constant(new Mock <IQueryable>().Object)); var request = new QueryRequest(queryableSource); queryContext = new QueryContext(api, request); testClass = new QueryExpressionContext(queryContext); var type = typeof(DataSourceStub); var methodInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Static).Where(x => x.Name == "GetQueryableSource"); testGetQuerableSource = methodInfo.First().MakeGenericMethod(new Type[] { typeof(Test) }); }
public Expression Source(QueryExpressionContext context, bool embedded) { var orders = new[] { new Order {Id = 234} }; if (!embedded) { if (context.VisitedNode.ToString().StartsWith("Source(\"Orders\"")) { return Expression.Constant(orders.AsQueryable()); } } return context.VisitedNode; }
/// <summary> /// Sources an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <param name="embedded"> /// Indicates if the sourcing is occurring on an embedded node. /// </param> /// <returns> /// A data source expression that represents the visited node. /// </returns> public Expression ReplaceQueryableSource(QueryExpressionContext context, bool embedded) { Ensure.NotNull(context, nameof(context)); if (context.ModelReference.EntitySet == null) { // EF provider can only source *ResourceSet*. return(null); } if (!(context.QueryContext.Api is IEntityFrameworkApi frameworkApi)) { // Not an EF Api. return(null); } var dbContextType = frameworkApi.ContextType; var dbContext = frameworkApi.DbContext; var dbSetProperty = frameworkApi.ContextType.GetProperties() .FirstOrDefault(prop => prop.Name == context.ModelReference.EntitySet.Name); if (dbSetProperty == null) { // EF provider can only source EntitySet from *DbSet property*. return(null); } if (!embedded) { // TODO GitHubIssue#37 : Add API entity manager for tracking entities // the underlying DbContext shouldn't track the entities var dbSet = dbSetProperty.GetValue(dbContext); ////dbSet = dbSet.GetType().GetMethod("AsNoTracking").Invoke(dbSet, null); return(Expression.Constant(dbSet)); } else { return(Expression.MakeMemberAccess( Expression.Constant(dbContext), dbSetProperty)); } }
private IQueryable GetSingletonQuery(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (context.ModelReference == null) { return(null); } var dataSourceStubReference = context.ModelReference as DataSourceStubModelReference; if (dataSourceStubReference == null) { return(null); } var singleton = dataSourceStubReference.Element as IEdmSingleton; if (singleton == null) { return(null); } var singletonProperty = this.singletonProperties .SingleOrDefault(p => p.Name == singleton.Name); if (singletonProperty != null) { object target = null; if (!singletonProperty.GetMethod.IsStatic) { target = context.QueryContext.GetApiService <ApiBase>(); if (target == null || !this.targetType.IsInstanceOfType(target)) { return(null); } } var value = Array.CreateInstance(singletonProperty.PropertyType, 1); value.SetValue(singletonProperty.GetValue(target), 0); return(value.AsQueryable()); } return(null); }
public CommonQueryContext(QueryExpressionContext queryExpression, LockingClauseListContext lockingClauseList) { if (queryExpression == null) { throw new ArgumentNullException(nameof(queryExpression)); } WithClause = queryExpression.withClause(); QueryExpressionBody = queryExpression.queryExpressionBody(); QueryExpressionParens = queryExpression.queryExpressionParens(); OrderClause = queryExpression.orderClause(); LimitClause = queryExpression.limitClause(); ProcedureAnalyseClause = queryExpression.procedureAnalyseClause(); LockingClauseList = lockingClauseList; Start = queryExpression.Start; Stop = lockingClauseList?.Stop ?? queryExpression.Stop; }
public void InnerProcessorShortCircuits() { var api = new QueryFilterApi(serviceProvider); var instance = new ConventionBasedQueryExpressionProcessor(typeof(EmptyApi)); var queryable = api.GetQueryableSource("Tests"); var queryRequest = new QueryRequest(queryable); var queryContext = new QueryContext(api, queryRequest); var queryExpressionContext = new QueryExpressionContext(queryContext); var processorMock = new Mock <IQueryExpressionProcessor>(); var expression = Expression.Constant(42); processorMock.Setup(x => x.Process(queryExpressionContext)).Returns(expression); instance.Inner = processorMock.Object; var result = instance.Process(queryExpressionContext); result.Should().Be(expression); }
private IQueryable GetEntitySetQuery(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (context.ModelReference == null) { return(null); } var apiDataReference = context.ModelReference as ApiDataReference; if (apiDataReference == null) { return(null); } var entitySet = apiDataReference.Element as IEdmEntitySet; if (entitySet == null) { return(null); } var entitySetProperty = this.entitySetProperties .SingleOrDefault(p => p.Name == entitySet.Name); if (entitySetProperty != null) { object target = null; if (!entitySetProperty.GetMethod.IsStatic) { target = context.QueryContext.ApiContext .GetProperty(typeof(Api).AssemblyQualifiedName); if (target == null || !this.targetType.IsAssignableFrom(target.GetType())) { return(null); } } return(entitySetProperty.GetValue(target) as IQueryable); } return(null); }
public Expression ReplaceQueryableSource(QueryExpressionContext context, bool embedded) { var a = new[] { new Product { Id = 1, Addr = new Address { Zip = 0001 }, Addr2 = new Address { Zip = 0002 } } }; var b = new[] { new Customer { Id = 1, } }; var c = new[] { new Store { Id = 1, } }; if (!embedded) { if (context.VisitedNode.ToString() == "GetQueryableSource(\"Products\", null)") { return(Expression.Constant(a.AsQueryable())); } if (context.VisitedNode.ToString() == "GetQueryableSource(\"Customers\", null)") { return(Expression.Constant(b.AsQueryable())); } if (context.VisitedNode.ToString() == "GetQueryableSource(\"Stores\", null)") { return(Expression.Constant(c.AsQueryable())); } } return(context.VisitedNode); }
private IQueryable GetEntitySetQuery(QueryExpressionContext context) { Ensure.NotNull(context, "context"); if (context.ModelReference == null) { return(null); } var dataSourceStubReference = context.ModelReference as DataSourceStubModelReference; if (dataSourceStubReference == null) { return(null); } var entitySet = dataSourceStubReference.Element as IEdmEntitySet; if (entitySet == null) { return(null); } var entitySetProperty = this.entitySetProperties .SingleOrDefault(p => p.Name == entitySet.Name); if (entitySetProperty != null) { object target = null; if (!entitySetProperty.GetMethod.IsStatic) { target = context.QueryContext.GetApiService <ApiBase>(); if (target == null || !this.targetType.IsInstanceOfType(target)) { return(null); } } return(entitySetProperty.GetValue(target) as IQueryable); } return(null); }
public Expression ReplaceQueryableSource(QueryExpressionContext context, bool embedded) { var orders = new[] { new Order { Id = 234 } }; if (!embedded) { if (context.VisitedNode.ToString().StartsWith("GetQueryableSource(\"Orders\"", StringComparison.CurrentCulture)) { return(Expression.Constant(orders.AsQueryable())); } } return(context.VisitedNode); }
/// <inheritdoc/> public Expression ReplaceQueryableSource(QueryExpressionContext context, bool embedded) { var result = CallInner(context, embedded); if (result != null) { // Call the provider's sourcer to find the source of the query. return(result); } // This sourcer ONLY deals with queries that cannot be addressed by the provider // such as a singleton query that cannot be sourced by the EF provider, etc. var query = ModelCache.GetEntitySetQuery(context) ?? ModelCache.GetSingletonQuery(context); if (query != null) { return(Expression.Constant(query)); } return(null); }
/// <inheritdoc/> public Expression Source(QueryExpressionContext context, bool embedded) { var innerHandler = ((IDelegateHookHandler <IQueryExpressionSourcer>) this).InnerHandler; if (innerHandler != null) { var result = innerHandler.Source(context, embedded); if (result != null) { return(result); } } var query = GetEntitySetQuery(context); if (query != null) { return(Expression.Constant(query)); } return(null); }
public Expression Source(QueryExpressionContext context, bool embedded) { var a = new[] { new Product { Id = 1, Addr = new Address { Zip = 0001 }, Addr2 = new Address { Zip = 0002 } } }; if (!embedded) { if (context.VisitedNode.ToString() == "Source(\"Products\", null)") { return(Expression.Constant(a.AsQueryable())); } } return(context.VisitedNode); }
/// <summary> /// Sources an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <param name="embedded"> /// Indicates if the sourcing is occurring on an embedded node. /// </param> /// <returns> /// A data source expression that represents the visited node. /// </returns> public Expression Source(QueryExpressionContext context, bool embedded) { Ensure.NotNull(context, "context"); var dbContext = context.QueryContext .ApiContext.GetProperty <DbContext>(DbApiConstants.DbContextKey); var dbSetProperty = dbContext.GetType().GetProperties() .First(prop => prop.Name == context.ModelReference.EntitySet.Name); if (!embedded) { // TODO GitHubIssue#37 : Add API entity manager for tracking entities // the underlying DbContext shouldn't track the entities var dbSet = dbSetProperty.GetValue(dbContext); ////dbSet = dbSet.GetType().GetMethod("AsNoTracking").Invoke(dbSet, null); return(Expression.Constant(dbSet)); } else { return(Expression.MakeMemberAccess( Expression.Constant(dbContext), dbSetProperty)); } }
/// <summary> /// Sources an expression. /// </summary> /// <param name="context"> /// The query expression context. /// </param> /// <param name="embedded"> /// Indicates if the sourcing is occurring on an embedded node. /// </param> /// <returns> /// A data source expression that represents the visited node. /// </returns> public Expression Source(QueryExpressionContext context, bool embedded) { Ensure.NotNull(context, "context"); if (context.ModelReference.EntitySet == null) { // EF provider can only source *EntitySet*. return(null); } var dbContext = context.QueryContext.GetApiService <DbContext>(); var dbSetProperty = dbContext.GetType().GetProperties() .FirstOrDefault(prop => prop.Name == context.ModelReference.EntitySet.Name); if (dbSetProperty == null) { // EF provider can only source EntitySet from *DbSet property*. return(null); } if (!embedded) { // TODO GitHubIssue#37 : Add API entity manager for tracking entities // the underlying DbContext shouldn't track the entities var dbSet = dbSetProperty.GetValue(dbContext); ////dbSet = dbSet.GetType().GetMethod("AsNoTracking").Invoke(dbSet, null); return(Expression.Constant(dbSet)); } else { return(Expression.MakeMemberAccess( Expression.Constant(dbContext), dbSetProperty)); } }
/// <inheritdoc/> public Expression Process(QueryExpressionContext context) { Ensure.NotNull(context, nameof(context)); if (Inner != null) { var innerFilteredExpression = Inner.Process(context); if (innerFilteredExpression != null && innerFilteredExpression != context.VisitedNode) { return(innerFilteredExpression); } } if (context.ModelReference is DataSourceStubModelReference dataSourceStubReference) { if (!(dataSourceStubReference.Element is IEdmEntitySet entitySet)) { return(null); } if (!(entitySet.Type is IEdmCollectionType collectionType)) { return(null); } if (!(collectionType.ElementType.Definition is IEdmEntityType entityType)) { return(null); } return(AppendOnFilterExpression(context, entitySet, entityType)); } if (context.ModelReference is PropertyModelReference propertyModelReference && propertyModelReference.Property != null) { // Could be a single navigation property or a collection navigation property var propType = propertyModelReference.Property.Type; if (propType is IEdmCollectionTypeReference collectionTypeReference) { var collectionType = collectionTypeReference.Definition as IEdmCollectionType; propType = collectionType.ElementType; } if (!(propType.Definition is IEdmEntityType entityType)) { return(null); } // In case of type inheritance, get the base type while (entityType.BaseType != null) { entityType = (IEdmEntityType)entityType.BaseType; } //Get the model, query it for the entity set of a given type. var entitySet = context.QueryContext.Model.EntityContainer.EntitySets().FirstOrDefault(c => c.EntityType() == entityType); if (entitySet == null) { return(null); } return(AppendOnFilterExpression(context, entitySet, entityType)); } return(null); }