/// <summary> /// Add a filter expression to the query. /// </summary> /// <param name="expression">Where method call expression.</param> private void AddFilter(MethodCallExpression expression) { if (expression != null && expression.Arguments.Count >= 2) { LambdaExpression lambda = StripQuote(expression.Arguments[1]) as LambdaExpression; if (lambda != null) { string filter = FilterBuildingExpressionVisitor.Create(lambda.Body); if (this.query.Filter != null) { // If there's already a filter value, that means the // query has multiple where clauses which we'll just // join together with "and"s. this.query.Filter += " and " + filter; } else { this.query.Filter = filter; } return; } } ThrowForUnsupportedException(expression); }
/// <summary> /// Translate an expression tree into a compiled OData query. /// </summary> /// <param name="expression">The expression tree.</param> /// <returns>An OData query.</returns> public static string Create(Expression expression) { Debug.Assert(expression != null, "expression cannot be null!"); // Walk the expression tree and build the filter. FilterBuildingExpressionVisitor visitor = new FilterBuildingExpressionVisitor(); visitor.Visit(expression); return(visitor.filter.ToString()); }
/// <summary> /// Translate an expression tree into a compiled OData query. /// </summary> /// <param name="expression"> /// The expression tree. /// </param> /// <param name="contractResolver"> /// The contract resolver used to determine property names from /// members used within expressions. /// </param> /// <returns> /// An OData query. /// </returns> public static string Create(Expression expression, MobileServiceContractResolver contractResolver) { Debug.Assert(expression != null); Debug.Assert(contractResolver != null); // Walk the expression tree and build the filter. FilterBuildingExpressionVisitor visitor = new FilterBuildingExpressionVisitor(contractResolver); visitor.Visit(expression); return(visitor.filter.ToString()); }
/// <summary> /// Get an element from a table by its id. /// </summary> /// <param name="id"> /// The id of the element. /// </param> /// <param name="parameters"> /// A dictionary of user-defined parameters and values to include in /// the request URI query string. /// </param> /// <returns> /// The desired element as JSON object. /// </returns> private async Task <JObject> GetSingleValueAsync(object id, IDictionary <string, string> parameters) { Debug.Assert(id != null); // Create a query for just this item string query = string.Format( CultureInfo.InvariantCulture, "$filter=({0} eq {1})", MobileServiceSystemColumns.Id, FilterBuildingExpressionVisitor.ToODataConstant(id)); // Send the query QueryResult response = await this.ReadAsync(query, parameters, MobileServiceFeatures.TypedTable); return(GetSingleValue(response)); }
/// <summary> /// Add an ordering constraint for an OrderBy/ThenBy call. /// </summary> /// <param name="expression"> /// The ordering method call. /// </param> /// <param name="ascending"> /// Whether the order is ascending or descending. /// </param> /// <param name="prepend"> /// Indicates if the expression should be prepended or not. /// </param> private void AddOrdering(MethodCallExpression expression, bool ascending, bool prepend = false) { // Keep updating with the deepest nested expression structure we // can get to so that we can provide a more detailed error message Expression deepest = expression; // We only allow OrderBy(x => x.Member) expressions. Anything else // will result in a NotSupportedException. if (expression != null && expression.Arguments.Count >= 2) { LambdaExpression lambda = StripQuote(expression.Arguments[1]) as LambdaExpression; if (lambda != null) { deepest = lambda.Body ?? lambda; // Find the name of the member being ordered MemberExpression memberAccess = lambda.Body as MemberExpression; if (memberAccess != null) { string memberName = FilterBuildingExpressionVisitor.GetTableMemberName(memberAccess, this.ContractResolver); if (memberName != null) { // Add the ordering if (prepend) { this.queryDescription.Ordering.Insert(0, new KeyValuePair <string, bool>(memberName, ascending)); } else { this.queryDescription.Ordering.Add(new KeyValuePair <string, bool>(memberName, ascending)); } return; } } } } throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, Resources.MobileServiceTableQueryTranslator_MembersOnlyInExpression, expression != null && expression.Method != null ? expression.Method.Name : null, deepest != null ? deepest.ToString() : null)); }
/// <summary> /// Get an element from a table by its id. /// </summary> /// <param name="id"> /// The id of the element. /// </param> /// <param name="parameters"> /// A dictionary of user-defined parameters and values to include in /// the request URI query string. /// </param> /// <returns> /// The desired element as JSON object. /// </returns> private async Task <string> GetSingleValueAsync(object id, IDictionary <string, string> parameters) { Debug.Assert(id != null); // Create a query for just this item string query = string.Format( CultureInfo.InvariantCulture, "$filter={0} eq {1}", MobileServiceUrlBuilder.IdPropertyName, FilterBuildingExpressionVisitor.ToODataConstant(id)); // Send the query JToken response = await this.ReadAsync(query, parameters); // Get the first element in the response JObject obj = response as JObject; if (obj == null) { JArray array = response as JArray; if (array != null && array.Count > 0) { obj = array.FirstOrDefault() as JObject; } } if (obj == null) { string responseStr = response != null?response.ToString() : "null"; throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, Resources.MobileServiceTable_NotSingleObject, responseStr)); } return(obj.ToString()); }
/// <summary> /// Translate an expression tree into a compiled OData query. /// </summary> /// <param name="expression">The expression tree.</param> /// <returns>An OData query.</returns> public static string Create(Expression expression) { Debug.Assert(expression != null, "expression cannot be null!"); // Walk the expression tree and build the filter. FilterBuildingExpressionVisitor visitor = new FilterBuildingExpressionVisitor(); visitor.Visit(expression); return visitor.filter.ToString(); }
/// <summary> /// Translate an expression tree into a compiled OData query. /// </summary> /// <param name="expression"> /// The expression tree. /// </param> /// <param name="contractResolver"> /// The contract resolver used to determine property names from /// members used within expressions. /// </param> /// <returns> /// An OData query. /// </returns> public static string Create(Expression expression, MobileServiceContractResolver contractResolver) { Debug.Assert(expression != null); Debug.Assert(contractResolver != null); // Walk the expression tree and build the filter. FilterBuildingExpressionVisitor visitor = new FilterBuildingExpressionVisitor(contractResolver); visitor.Visit(expression); return visitor.filter.ToString(); }
/// <summary> /// Add a projection to the query. /// </summary> /// <param name="expression"> /// Select method call expression. /// </param> private void AddProjection(MethodCallExpression expression) { // We only support Select(x => ...) projections. Anything else // will throw a NotSupportException. if (expression != null && expression.Arguments.Count == 2) { LambdaExpression projection = StripQuote(expression.Arguments[1]) as LambdaExpression; if (projection != null && projection.Parameters.Count == 1) { // Compile the projection into a function that we can apply // to the deserialized value to transform it accordingly. this.queryDescription.Projections.Add(projection.Compile()); // We only need to capture the projection argument type and members for the // very first projection. if (this.queryDescription.ProjectionArgumentType == null) { // Store the type of the very first input to the projection as we'll // need that for deserialization of values (since the // projection will change the expected type of the data // source) this.queryDescription.ProjectionArgumentType = projection.Parameters[0].Type; // Filter the selection down to just the values used by // the projection IExpressionUtility expressionUtility = Platform.Instance.ExpressionUtility; foreach (MemberExpression memberExpression in expressionUtility.GetMemberExpressions(projection.Body)) { // Ensure we only process members of the parameter string memberName = FilterBuildingExpressionVisitor.GetTableMemberName(memberExpression, this.ContractResolver); if (memberName != null) { queryDescription.Selection.Add(memberName); } } //Make sure we also include all the members that would be //required for deserialization JsonContract contract = this.ContractResolver.ResolveContract(this.queryDescription.ProjectionArgumentType); JsonObjectContract objectContract = contract as JsonObjectContract; if (objectContract != null) { foreach (string propertyName in objectContract.Properties .Where(p => p.Required == Required.Always || p.Required == Required.AllowNull) .Select(p => p.PropertyName)) { if (!this.queryDescription.Selection.Contains(propertyName)) { this.queryDescription.Selection.Add(propertyName); } } } } return; } } ThrowForUnsupportedException(expression); }