// coerce fromExpr to toExpr type // but also convert both to nonnullable types. private void ConvertExpr(ref Expression fromExpr, ref Expression toExpr) { var constExpr = fromExpr as ConstantExpression; var toType = TypeFns.GetNonNullableType(toExpr.Type); if (constExpr != null) { if (constExpr.Value == null) { return; } var newValue = Convert.ChangeType(constExpr.Value, toType); fromExpr = Expression.Constant(newValue); } else { fromExpr = Expression.Convert(fromExpr, toType); } if (TypeFns.IsNullableType(toExpr.Type)) { toExpr = Expression.Convert(toExpr, toType); } }
/// <summary> /// Apply the queryOptions to the query. /// This method handles nested order-by statements the the current ASP.NET web api does not yet support. /// </summary> /// <param name="queryable"></param> /// <param name="queryOptions"></param> /// <param name="querySettings"></param> /// <returns></returns> public static IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions, ODataQuerySettings querySettings) { // if we see an extended order by we also need to process any skip/take operators as well. var orderByQueryString = queryOptions.RawValues.OrderBy; // HACK: this is a hack because on a bug in querySettings.EnsureStableOrdering = true that overrides // any existing order by clauses, instead of appending to them. querySettings.EnsureStableOrdering = false; if (orderByQueryString == null || orderByQueryString.IndexOf('/') < 0) { // Just let the default implementation handle it. return(queryOptions.ApplyTo(queryable, querySettings)); } var newQueryOptions = QueryHelper.RemoveExtendedOps(queryOptions); var result = QueryHelper.ApplyQuery(queryable, newQueryOptions, querySettings); var elementType = TypeFns.GetElementType(queryable.GetType()); string inlinecountString = queryOptions.RawValues.InlineCount; if (!string.IsNullOrWhiteSpace(inlinecountString)) { if (inlinecountString == "allpages") { if (result is IQueryable) { var inlineCount = (Int64)Queryable.Count((dynamic)result); queryOptions.Request.SetInlineCount(inlineCount); } } } var orderByClauses = orderByQueryString.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, obc); result = func(result); isThenBy = true; }); var skipQueryString = queryOptions.RawValues.Skip; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } var topQueryString = queryOptions.RawValues.Top; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } return(result); }
/// <summary> /// Constructs a generic list. /// </summary> /// <param name="type"></param> /// <returns></returns> public static IList MakeGenericList(Type type) { return((IList)TypeFns.ConstructGenericInstance(typeof(List <>), type)); }
/// <summary> /// Called when the action is executed. /// </summary> /// <param name="actionExecutedContext">The action executed context.</param> public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response == null) { return; } if (!actionExecutedContext.Response.IsSuccessStatusCode) { return; } object responseObject; if (!actionExecutedContext.Response.TryGetContentValue(out responseObject)) { return; } var dQuery = ((dynamic)responseObject); if (dQuery.GetType().IsInstanceOfType(typeof(IQueryable))) { return; } var elementType = TypeFns.GetElementType(responseObject.GetType()); NameValueCollection querystringParams = HttpUtility.ParseQueryString(actionExecutedContext.Request.RequestUri.Query); string filterQueryString = querystringParams["$filter"]; if (!string.IsNullOrWhiteSpace(filterQueryString)) { var func = BuildFilterFunc(filterQueryString, elementType); dQuery = func(dQuery as IQueryable); } int? inlineCount = null; string inlinecountString = querystringParams["$inlinecount"]; if (!string.IsNullOrWhiteSpace(inlinecountString)) { if (inlinecountString == "allpages") { if (dQuery is IQueryable) { inlineCount = Queryable.Count(dQuery); } } } string orderByQueryString = querystringParams["$orderby"]; if (!string.IsNullOrWhiteSpace(orderByQueryString)) { var orderByClauses = orderByQueryString.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var func = BuildOrderByFunc(isThenBy, elementType, obc); dQuery = func(dQuery as IQueryable); isThenBy = true; }); } string skipQueryString = querystringParams["$skip"]; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); dQuery = func(dQuery as IQueryable); } string topQueryString = querystringParams["$top"]; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); dQuery = func(dQuery as IQueryable); } string selectQueryString = querystringParams["$select"]; if (!string.IsNullOrWhiteSpace(selectQueryString)) { var selectClauses = selectQueryString.Split(',').Select(sc => sc.Replace('/', '.')).ToList(); var func = BuildSelectFunc(elementType, selectClauses); dQuery = func(dQuery as IQueryable); } string expandsQueryString = querystringParams["$expand"]; if (!string.IsNullOrWhiteSpace(expandsQueryString)) { if (!string.IsNullOrWhiteSpace(selectQueryString)) { throw new Exception("Use of both 'expand' and 'select' in the same query is not currently supported"); } expandsQueryString.Split(',').Select(s => s.Trim()).ToList().ForEach(expand => { dQuery = dQuery.Include(expand.Replace('/', '.')); }); } // execute any DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. Object rQuery; if (dQuery is IQueryable) { rQuery = System.Linq.Enumerable.ToList((dynamic)dQuery); } else { rQuery = dQuery; } var formatter = ((dynamic)actionExecutedContext.Response.Content).Formatter; var oc = new System.Net.Http.ObjectContent(rQuery.GetType(), rQuery, formatter); actionExecutedContext.Response.Content = oc; if (inlineCount.HasValue) { actionExecutedContext.Response.Headers.Add("X-InlineCount", inlineCount.ToString()); } }
private IQueryable ApplyExtendedOrderBy(IQueryable queryable, ODataQueryOptions queryOptions) { // if we see an extended order by we also need to process any skip/take operators as well. var orderByQueryString = queryOptions.RawValues.OrderBy; if (orderByQueryString == null || orderByQueryString.IndexOf("/") == -1) { return(null); } var request = queryOptions.Request; var oldUri = request.RequestUri; var map = oldUri.ParseQueryString(); var newQuery = map.Keys.Cast <String>() .Where(k => (k != "$orderby") && (k != "$top") && (k != "$skip")) .Select(k => k + "=" + map[k]) .ToAggregateString("&"); var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath + "?" + newQuery; var newRequest = new HttpRequestMessage(request.Method, new Uri(newUrl)); var newQo = new ODataQueryOptions(queryOptions.Context, newRequest); var result = base.ApplyQuery(queryable, newQo); var elementType = TypeFns.GetElementType(queryable.GetType()); if (!string.IsNullOrWhiteSpace(orderByQueryString)) { var orderByClauses = orderByQueryString.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, obc); result = func(result); isThenBy = true; }); } var skipQueryString = queryOptions.RawValues.Skip; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } var topQueryString = queryOptions.RawValues.Top; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } request.Properties.Add("breeze_orderBy", true); return(result); }
protected virtual Expression VisitNode(ParseTreeNode node) { if (node == null) { return(null); } var nodes = node.ChildNodes; Expression targetExpr, searchExpr, startExpr, lengthExpr; String methodName; switch (node.Term.Name) { case "BinaryExpr": { var leftExpr = VisitNode(nodes[0]); var operatorName = nodes[1].Token.ValueString; var rightExpr = VisitNode(nodes[2]); return(VisitBinary(node, operatorName, leftExpr, rightExpr)); } case "UnaryExpr": { var operatorName = nodes[0].Token.ValueString.ToLower(); targetExpr = VisitNode(nodes[1]); return(VisitUnary(node, targetExpr, operatorName)); } case "MemberExpr": { targetExpr = _paramExpr; ParameterExpression paramExpr; nodes[0].ChildNodes.ForEach(n => { var name = n.Term.Name; if (name == "Identifier") { if (_lambdaVarMap.TryGetValue(n.Token.ValueString, out paramExpr)) { targetExpr = paramExpr; } else { targetExpr = VisitMemberExpr(n, targetExpr, n.Token.ValueString); } } else if (name == "AnyMethodCallExpr" || name == "AllMethodCallExpr") { methodName = n.ChildNodes[0].Token.ValueString; var lambdaExprNode = n.ChildNodes[1]; var lambdaVariableName = lambdaExprNode.ChildNodes[0].Token.ValueString; var exprNode = lambdaExprNode.ChildNodes[1]; var itemType = TypeFns.GetElementType(targetExpr.Type); paramExpr = Expression.Parameter(itemType, lambdaVariableName); _lambdaVarMap.Add(lambdaVariableName, paramExpr); var lambdaSubExpr = VisitNode(exprNode); var lambdaExpr = Expression.Lambda(lambdaSubExpr, paramExpr); targetExpr = VisitAnyAll(n, targetExpr, methodName, lambdaExpr); } else { throw new Exception("Unable to process node: " + n.Term.Name); } }); return(targetExpr); } case "StringLiteral": case "NumberLiteral": { return(VisitSimpleLiteral(node, node.Token.Value)); } case "Constant": { return(VisitConstant(node, node.Token.ValueString)); } case "DateTimeLiteral": { return(VisitDateTimeLiteral(node, node.Token.ValueString)); } case "TimeLiteral": { return(VisitTimeLiteral(node, node.Token.ValueString)); } case "GuidLiteral": { return(VisitGuidLiteral(node, node.Token.ValueString)); } case "DateTimeOffsetLiteral": { return(VisitDateTimeOffsetLiteral(node, node.Token.ValueString)); } case "SubstringOfMethodCallExpr": { searchExpr = VisitNode(nodes[1]); targetExpr = VisitNode(nodes[2]); return(VisitSubstringOf(node, targetExpr, searchExpr)); } case "StartsWithMethodCallExpr": { targetExpr = VisitNode(nodes[1]); searchExpr = VisitNode(nodes[2]); return(VisitStartsWith(node, targetExpr, searchExpr)); } case "EndsWithMethodCallExpr": { targetExpr = VisitNode(nodes[1]); searchExpr = VisitNode(nodes[2]); return(VisitEndsWith(node, targetExpr, searchExpr)); } case "IndexOfMethodCallExpr": { targetExpr = VisitNode(nodes[1]); searchExpr = VisitNode(nodes[2]); return(VisitIndexOf(node, targetExpr, searchExpr)); } case "Substring1MethodCallExpr": { targetExpr = VisitNode(nodes[1]); startExpr = VisitNode(nodes[2]); return(VisitSubstring1(node, targetExpr, startExpr)); } case "Substring2MethodCallExpr": { targetExpr = VisitNode(nodes[1]); startExpr = VisitNode(nodes[2]); lengthExpr = VisitNode(nodes[3]); return(VisitSubstring2(node, targetExpr, startExpr, lengthExpr)); } case "ConcatMethodCallExpr": { var expr1 = VisitNode(nodes[1]); var expr2 = VisitNode(nodes[2]); return(VisitConcat(node, expr1, expr2)); } case "ReplaceMethodCallExpr": { targetExpr = VisitNode(nodes[1]); var findExpr = VisitNode(nodes[2]); var replaceExpr = VisitNode(nodes[3]); return(VisitReplace(node, targetExpr, findExpr, replaceExpr)); } case "LengthMethodCallExpr": { targetExpr = VisitNode(nodes[1]); return(VisitLength(node, targetExpr)); } case "TrimMethodCallExpr": { targetExpr = VisitNode(nodes[1]); return(VisitTrim(node, targetExpr)); } case "ToLowerMethodCallExpr": { targetExpr = VisitNode(nodes[1]); return(VisitToLower(node, targetExpr)); } case "ToUpperMethodCallExpr": { targetExpr = VisitNode(nodes[1]); return(VisitToUpper(node, targetExpr)); } case "SecondMethodCallExpr": case "MinuteMethodCallExpr": case "HourMethodCallExpr": case "DayMethodCallExpr": case "MonthMethodCallExpr": case "YearMethodCallExpr": { methodName = nodes[0].Token.ValueString.ToLower(); targetExpr = VisitNode(nodes[1]); return(VisitDatePart(node, targetExpr, methodName)); } case "RoundMethodCallExpr": case "FloorMethodCallExpr": case "CeilingMethodCallExpr": { methodName = nodes[0].Token.ValueString.ToLower(); targetExpr = VisitNode(nodes[1]); return(VisitMath(node, targetExpr, methodName)); } default: throw new Exception("Unknown Expression type: " + node.Term.Name); } }
private void CoerceTypes(string operatorName, ref Expression leftExpr, ref Expression rightExpr) { if (leftExpr.Type != rightExpr.Type) { var leftType = TypeFns.GetNonNullableType(leftExpr.Type); var rightType = TypeFns.GetNonNullableType(rightExpr.Type); if (leftType == typeof(String)) { ConvertExpr(ref rightExpr, ref leftExpr); } else if (rightType == typeof(String)) { ConvertExpr(ref leftExpr, ref rightExpr); } else if ((TypeFns.IsNumericType(leftType) || TypeFns.IsEnumType(leftType)) && (TypeFns.IsNumericType(rightType) || TypeFns.IsEnumType(rightType))) { var leftIx = NumericTypes.IndexOf(leftType); var rightIx = NumericTypes.IndexOf(rightType); if (leftIx < rightIx) { ConvertExpr(ref leftExpr, ref rightExpr); } else { ConvertExpr(ref rightExpr, ref leftExpr); } } else if (leftType == typeof(Guid) || leftType == typeof(DateTime) || leftType == typeof(Boolean) || leftType == typeof(TimeSpan) || TypeFns.IsNumericType(leftType) || TypeFns.IsEnumType(leftType)) { ConvertExpr(ref rightExpr, ref leftExpr); } else { throw new Exception("Unable to perform operation: " + operatorName + "on types:" + leftExpr.Type + ", " + rightExpr.Type); } } }