Create an OData filter expression by walking an expression tree.
        /// <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());
        }
Esempio n. 4
0
        /// <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));
        }
Esempio n. 5
0
        /// <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));
        }
Esempio n. 6
0
        /// <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();
 }
Esempio n. 9
0
        /// <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);
        }