/// <summary>Filters a query like a SQL WHERE clause does.</summary> /// <param name="service">Service with data and configuration.</param> /// <param name="requestDescription">RequestDescription instance containing information about the current request being parsed.</param> /// <param name="source">Original source for query expression.</param> /// <returns>The composed query expression.</returns> internal static Expression Where(IDataService service, RequestDescription requestDescription, Expression source) { Debug.Assert(service != null, "service != null"); Debug.Assert(source != null, "source != null"); Debug.Assert(requestDescription != null, "requestDescription != null"); FilterClause filterClause = new RequestExpressionParser(service, requestDescription).ParseFilter(); if (filterClause == null) { return(source); } bool filterQueryApplicable = requestDescription.TargetKind == RequestTargetKind.Resource || requestDescription.TargetKind == RequestTargetKind.OpenProperty || requestDescription.TargetKind == RequestTargetKind.ComplexObject || requestDescription.CountOption == RequestQueryCountOption.CountSegment; if (!filterQueryApplicable) { throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryFilterOptionNotApplicable); } Type queryElementType = source.ElementType(); Debug.Assert(queryElementType != null, "queryElementType != null"); ParameterExpression parameterForIt = Expression.Parameter(queryElementType, "it"); Debug.Assert( (requestDescription.TargetResourceSet == null && (requestDescription.TargetResourceType == null || requestDescription.TargetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)) || (requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.ResourceTypeKind == ResourceTypeKind.EntityType), "setForIt cannot be null if typeForIt is an entity type."); Debug.Assert( requestDescription.TargetResourceType == null && parameterForIt.Type == typeof(object) || requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.InstanceType == parameterForIt.Type, "non-open type expressions should have a typeForIt"); var translator = NodeToExpressionTranslator.Create(service, requestDescription, parameterForIt); LambdaExpression lambda = translator.TranslateFilterClause(filterClause); return(source.QueryableWhere(lambda)); }
/// <summary>Filters a query like a SQL WHERE clause does.</summary> /// <param name="service">Service with data and configuration.</param> /// <param name="requestDescription">RequestDescription instance containing information about the current request being parsed.</param> /// <param name="source">Original source for query expression.</param> /// <returns>The composed query expression.</returns> internal static Expression Where(IDataService service, RequestDescription requestDescription, Expression source) { Debug.Assert(service != null, "service != null"); Debug.Assert(source != null, "source != null"); Debug.Assert(requestDescription != null, "requestDescription != null"); FilterClause filterClause = new RequestExpressionParser(service, requestDescription).ParseFilter(); if (filterClause == null) { return source; } bool filterQueryApplicable = requestDescription.TargetKind == RequestTargetKind.Resource || requestDescription.TargetKind == RequestTargetKind.OpenProperty || requestDescription.TargetKind == RequestTargetKind.ComplexObject || requestDescription.CountOption == RequestQueryCountOption.CountSegment; if (!filterQueryApplicable) { throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryFilterOptionNotApplicable); } Type queryElementType = source.ElementType(); Debug.Assert(queryElementType != null, "queryElementType != null"); ParameterExpression parameterForIt = Expression.Parameter(queryElementType, "it"); Debug.Assert( (requestDescription.TargetResourceSet == null && (requestDescription.TargetResourceType == null || requestDescription.TargetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)) || (requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.ResourceTypeKind == ResourceTypeKind.EntityType), "setForIt cannot be null if typeForIt is an entity type."); Debug.Assert( requestDescription.TargetResourceType == null && parameterForIt.Type == typeof(object) || requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.InstanceType == parameterForIt.Type, "non-open type expressions should have a typeForIt"); var translator = NodeToExpressionTranslator.Create(service, requestDescription, parameterForIt); LambdaExpression lambda = translator.TranslateFilterClause(filterClause); return source.QueryableWhere(lambda); }
/// <summary> /// Builds the collection of ordering expressions including implicit ordering if paging is required at top level /// </summary> private void ObtainOrderingExpressions() { const String Comma = ","; const char Space = ' '; const String AscendingOrderIdentifier = "asc"; const string QuestionMark = "?"; const string EqualMark = "="; const string AndMark = "&"; if (!string.IsNullOrEmpty(this.service.OperationContext.RequestMessage.GetQueryStringItem(XmlConstants.HttpQueryStringOrderBy))) { this.CheckSetQueryApplicable(); } Debug.Assert(this.topLevelOrderingInfo == null, "Must only be called once per query"); ResourceType rt = this.description.TargetResourceType; this.topLevelOrderingInfo = new OrderingInfo(this.IsStandardPaged); OrderByClause orderByClause = new RequestExpressionParser(this.service, this.description).ParseOrderBy(); // We need to generate ordering expression(when we don't have top level $orderby), if either the result is paged, or we have // skip or top count request because in that case, the skip or top has to happen in // the expand provider. if (orderByClause == null) { if (this.IsStandardPaged || this.topCount.HasValue || this.skipCount.HasValue) { Uri requestUri = this.service.OperationContext.AbsoluteRequestUri; StringBuilder orderBy = string.IsNullOrEmpty(requestUri.Query) ? new StringBuilder(requestUri.AbsoluteUri + QuestionMark) : new StringBuilder(requestUri.AbsoluteUri + AndMark); orderBy.Append(XmlConstants.HttpQueryStringOrderBy + EqualMark); String separator = String.Empty; foreach (var keyProp in this.description.TargetResourceSet.GetKeyPropertiesForOrderBy()) { orderBy.Append(separator).Append(keyProp.Name).Append(Space).Append(AscendingOrderIdentifier); separator = Comma; } var uriParser = RequestUriProcessor.CreateUriParserWithBatchReferenceCallback(this.service, new Uri(orderBy.ToString())); orderByClause = uriParser.ParseOrderBy(); } else { return; } } ParameterExpression elementParameter = Expression.Parameter(rt.InstanceType, "element"); var translator = NodeToExpressionTranslator.Create(this.service, this.description, elementParameter); IEnumerable<OrderingExpression> ordering = translator.TranslateOrderBy(orderByClause); this.topLevelOrderingInfo.AddRange(ordering); if (this.IsStandardPaged) { this.description.SkipTokenExpressionCount = this.topLevelOrderingInfo.OrderingExpressions.Count; this.description.SkipTokenProperties = NeedSkipTokenVisitor.CollectSkipTokenProperties(this.topLevelOrderingInfo, rt); } }