Ejemplo n.º 1
0
        /// <summary>
        /// Pushes an arbitrary payload to every device matching target. This is shorthand for:
        ///
        /// <code>
        /// var push = new AVPush();
        /// push.Query = query
        /// push.Data = data;
        /// return push.SendAsync();
        /// </code>
        /// </summary>
        /// <param name="data">A push payload. See the AVPush.Data property for more information.</param>
        /// <param name="query">A query filtering the devices which should receive this Push Notification.</param>
        public static Task SendDataAsync(IDictionary <string, object> data, AVQuery <AVInstallation> query)
        {
            var push = new AVPush();

            push.Query = query;
            push.Data  = data;
            return(push.SendAsync());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Pushes a simple message to every device matching the target query. This is shorthand for:
        ///
        /// <code>
        /// var push = new AVPush();
        /// push.Query = query;
        /// push.Data = new Dictionary&lt;string, object&gt;{{"alert", alert}};
        /// return push.SendAsync();
        /// </code>
        /// </summary>
        /// <param name="alert">The alert message to send.</param>
        /// <param name="query">A query filtering the devices which should receive this Push Notification.</param>
        public static Task SendAlertAsync(string alert, AVQuery <AVInstallation> query)
        {
            var push = new AVPush();

            push.Query = query;
            push.Alert = alert;
            return(push.SendAsync());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Filters a query based upon the predicate provided.
        /// </summary>
        /// <typeparam name="TSource">The type of AVObject being queried for.</typeparam>
        /// <param name="source">The base <see cref="AVQuery{TSource}"/> to which
        /// the predicate will be added.</param>
        /// <param name="predicate">A function to test each AVObject for a condition.
        /// The predicate must be able to be represented by one of the standard Where
        /// functions on AVQuery</param>
        /// <returns>A new AVQuery whose results will match the given predicate as
        /// well as the Source's filters.</returns>
        public static AVQuery <TSource> Where <TSource>(
            this AVQuery <TSource> source, Expression <Func <TSource, bool> > predicate)
            where TSource : AVObject
        {
            // Handle top-level logic operators && and ||
            var binaryExpression = predicate.Body as BinaryExpression;

            if (binaryExpression != null)
            {
                if (binaryExpression.NodeType == ExpressionType.AndAlso)
                {
                    return(source
                           .Where(Expression.Lambda <Func <TSource, bool> >(
                                      binaryExpression.Left, predicate.Parameters))
                           .Where(Expression.Lambda <Func <TSource, bool> >(
                                      binaryExpression.Right, predicate.Parameters)));
                }
                if (binaryExpression.NodeType == ExpressionType.OrElse)
                {
                    var left = source.Where(Expression.Lambda <Func <TSource, bool> >(
                                                binaryExpression.Left, predicate.Parameters));
                    var right = source.Where(Expression.Lambda <Func <TSource, bool> >(
                                                 binaryExpression.Right, predicate.Parameters));
                    return(left.Or(right));
                }
            }

            var normalized = new WhereNormalizer().Visit(predicate.Body);

            var methodCallExpr = normalized as MethodCallExpression;

            if (methodCallExpr != null)
            {
                return(source.WhereMethodCall(predicate, methodCallExpr));
            }

            var binaryExpr = normalized as BinaryExpression;

            if (binaryExpr != null)
            {
                return(source.WhereBinaryExpression(predicate, binaryExpr));
            }

            var unaryExpr = normalized as UnaryExpression;

            if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Not)
            {
                var node = unaryExpr.Operand as MethodCallExpression;
                if (IsParseObjectGet(node) && (node.Type == typeof(bool) || node.Type == typeof(bool?)))
                {
                    // This is a raw boolean field access like 'where !obj.Get<bool>("foo")'
                    return(source.WhereNotEqualTo(GetValue(node.Arguments[0]) as string, true));
                }
            }

            throw new InvalidOperationException(
                      "Encountered an unsupported expression for ParseQueries.");
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Adds a constraint to the query that requires that a particular key's value
 /// matches another AVQuery. This only works on keys whose values are
 /// AVObjects or lists of AVObjects.
 /// </summary>
 /// <param name="key">The key to check.</param>
 /// <param name="query">The query that the value should match.</param>
 /// <returns>A new query with the additional constraint.</returns>
 public AVQuery <T> WhereMatchesQuery <TOther>(string key, AVQuery <TOther> query)
     where TOther : AVObject
 {
     return(new AVQuery <T>(this, where : new Dictionary <string, object> {
         { key, new Dictionary <string, object> {
               { "$inQuery", query.BuildParameters(true) }
           } }
     }));
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Adds a constraint to the query that requires that a particular key's value
 /// matches another AVQuery. This only works on keys whose values are
 /// AVObjects or lists of AVObjects.
 /// </summary>
 /// <param name="key">The key to check.</param>
 /// <param name="query">The query that the value should match.</param>
 /// <returns>A new query with the additional constraint.</returns>
 public virtual S WhereMatchesQuery <TOther>(string key, AVQuery <TOther> query)
     where TOther : AVObject
 {
     return(CreateInstance(this, where : new Dictionary <string, object> {
         { key, new Dictionary <string, object> {
               { "$inQuery", query.BuildParameters(true) }
           } }
     }));
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Private constructor for composition of queries. A Source query is required,
 /// but the remaining values can be null if they won't be changed in this
 /// composition.
 /// </summary>
 private AVQuery(AVQuery <T> source,
                 IDictionary <string, object> where      = null,
                 IEnumerable <string> replacementOrderBy = null,
                 IEnumerable <string> thenBy             = null,
                 int?skip  = null,
                 int?limit = null,
                 IEnumerable <string> includes     = null,
                 IEnumerable <string> selectedKeys = null,
                 String redirectClassNameForKey    = null)
     : base(source, where, replacementOrderBy, thenBy, skip, limit, includes, selectedKeys, redirectClassNameForKey)
 {
 }
Ejemplo n.º 7
0
 internal override AVQuery <T> CreateInstance(
     AVQuery <T> source,
     IDictionary <string, object> where      = null,
     IEnumerable <string> replacementOrderBy = null,
     IEnumerable <string> thenBy             = null,
     int?skip  = null,
     int?limit = null,
     IEnumerable <string> includes     = null,
     IEnumerable <string> selectedKeys = null,
     String redirectClassNameForKey    = null)
 {
     return(new AVQuery <T>(this, where, replacementOrderBy, thenBy, skip, limit, includes, selectedKeys, redirectClassNameForKey));
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Adds a constraint to the query that requires a particular key's value
        /// does not match any value for a key in the results of another AVQuery.
        /// </summary>
        /// <param name="key">The key whose value is being checked.</param>
        /// <param name="keyInQuery">The key in the objects from the subquery to look in.</param>
        /// <param name="query">The subquery to run</param>
        /// <returns>A new query with the additional constraint.</returns>
        public AVQuery <T> WhereDoesNotMatchesKeyInQuery <TOther>(string key,
                                                                  string keyInQuery,
                                                                  AVQuery <TOther> query) where TOther : AVObject
        {
            var parameters = new Dictionary <string, object> {
                { "query", query.BuildParameters(true) },
                { "key", keyInQuery }
            };

            return(new AVQuery <T>(this, where : new Dictionary <string, object> {
                { key, new Dictionary <string, object> {
                      { "$dontSelect", parameters }
                  } }
            }));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Adds a constraint to the query that requires a particular key's value
        /// to match a value for a key in the results of another AVQuery.
        /// </summary>
        /// <param name="key">The key whose value is being checked.</param>
        /// <param name="keyInQuery">The key in the objects from the subquery to look in.</param>
        /// <param name="query">The subquery to run</param>
        /// <returns>A new query with the additional constraint.</returns>
        public virtual S WhereMatchesKeyInQuery <TOther>(string key,
                                                         string keyInQuery,
                                                         AVQuery <TOther> query) where TOther : AVObject
        {
            var parameters = new Dictionary <string, object> {
                { "query", query.BuildParameters(true) },
                { "key", keyInQuery }
            };

            return(CreateInstance(this, where : new Dictionary <string, object> {
                { key, new Dictionary <string, object> {
                      { "$select", parameters }
                  } }
            }));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Converts a normalized binary expression into the appropriate AVQuery clause.
        /// </summary>
        private static AVQuery <T> WhereBinaryExpression <T>(
            this AVQuery <T> source, Expression <Func <T, bool> > expression, BinaryExpression node)
            where T : AVObject
        {
            var leftTransformed = new ObjectNormalizer().Visit(node.Left) as MethodCallExpression;

            if (!(IsParseObjectGet(leftTransformed) &&
                  leftTransformed.Object == expression.Parameters[0]))
            {
                throw new InvalidOperationException(
                          "Where expressions must have one side be a field operation on a AVObject.");
            }

            var fieldPath   = GetValue(leftTransformed.Arguments[0]) as string;
            var filterValue = GetValue(node.Right);

            if (filterValue != null && !AVEncoder.IsValidType(filterValue))
            {
                throw new InvalidOperationException(
                          "Where clauses must use types compatible with AVObjects.");
            }

            switch (node.NodeType)
            {
            case ExpressionType.GreaterThan:
                return(source.WhereGreaterThan(fieldPath, filterValue));

            case ExpressionType.GreaterThanOrEqual:
                return(source.WhereGreaterThanOrEqualTo(fieldPath, filterValue));

            case ExpressionType.LessThan:
                return(source.WhereLessThan(fieldPath, filterValue));

            case ExpressionType.LessThanOrEqual:
                return(source.WhereLessThanOrEqualTo(fieldPath, filterValue));

            case ExpressionType.Equal:
                return(source.WhereEqualTo(fieldPath, filterValue));

            case ExpressionType.NotEqual:
                return(source.WhereNotEqualTo(fieldPath, filterValue));

            default:
                throw new InvalidOperationException(
                          "Where expressions do not support this operator.");
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Constructs a AVObject whose id is already known by fetching data
        /// from the server.
        /// </summary>
        /// <param name="objectId">ObjectId of the AVObject to fetch.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The AVObject for the given objectId.</returns>
        public Task <T> GetAsync(string objectId, CancellationToken cancellationToken)
        {
            AVQuery <T> singleItemQuery = new AVQuery <T>(className).
                                          WhereEqualTo("objectId", objectId);

            singleItemQuery = new AVQuery <T>(singleItemQuery, includes: this.includes, selectedKeys: this.selectedKeys, limit: 1);
            return(singleItemQuery.FindAsync(cancellationToken).OnSuccess(t =>
            {
                var result = t.Result.FirstOrDefault();
                if (result == null)
                {
                    throw new AVException(AVException.ErrorCode.ObjectNotFound,
                                          "Object with the given objectId not found.");
                }
                return result;
            }));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Private constructor for composition of queries. A source query is required,
        /// but the remaining values can be null if they won't be changed in this
        /// composition.
        /// </summary>
        private AVQuery(AVQuery <T> source,
                        IDictionary <string, object> where      = null,
                        IEnumerable <string> replacementOrderBy = null,
                        IEnumerable <string> thenBy             = null,
                        int?skip  = null,
                        int?limit = null,
                        IEnumerable <string> includes     = null,
                        IEnumerable <string> selectedKeys = null)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            className         = source.className;
            this.where        = source.where;
            this.orderBy      = source.orderBy;
            this.skip         = source.skip;
            this.limit        = source.limit;
            this.includes     = source.includes;
            this.selectedKeys = source.selectedKeys;

            if (where != null)
            {
                var newWhere = MergeWhereClauses(where);
                this.where = new Dictionary <string, object>(newWhere);
            }

            if (replacementOrderBy != null)
            {
                this.orderBy = new ReadOnlyCollection <string>(replacementOrderBy.ToList());
            }

            if (thenBy != null)
            {
                if (this.orderBy == null)
                {
                    throw new ArgumentException("You must call OrderBy before calling ThenBy.");
                }
                var newOrderBy = new List <string>(this.orderBy);
                newOrderBy.AddRange(thenBy);
                this.orderBy = new ReadOnlyCollection <string>(newOrderBy);
            }

            // Remove duplicates.
            if (this.orderBy != null)
            {
                var newOrderBy = new HashSet <string>(this.orderBy);
                this.orderBy = new ReadOnlyCollection <string>(newOrderBy.ToList <string>());
            }

            if (skip != null)
            {
                this.skip = (this.skip ?? 0) + skip;
            }

            if (limit != null)
            {
                this.limit = limit;
            }

            if (includes != null)
            {
                var newIncludes = MergeIncludes(includes);
                this.includes = new ReadOnlyCollection <string>(newIncludes.ToList());
            }

            if (selectedKeys != null)
            {
                var newSelectedKeys = MergeSelectedKeys(selectedKeys);
                this.selectedKeys = new ReadOnlyCollection <string>(newSelectedKeys.ToList());
            }
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Constructs a query that is the or of the given queries.
 /// </summary>
 /// <typeparam name="T">The type of AVObject being queried.</typeparam>
 /// <param name="source">An initial query to 'or' with additional queries.</param>
 /// <param name="queries">The list of AVQueries to 'or' together.</param>
 /// <returns>A query that is the or of the given queries.</returns>
 public static AVQuery <T> Or <T>(this AVQuery <T> source, params AVQuery <T>[] queries)
     where T : AVObject
 {
     return(AVQuery <T> .Or(queries.Concat(new[] { source })));
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Correlates the elements of two queries based on matching keys.
        /// </summary>
        /// <typeparam name="TOuter">The type of AVObjects of the first query.</typeparam>
        /// <typeparam name="TInner">The type of AVObjects of the second query.</typeparam>
        /// <typeparam name="TKey">The type of the keys returned by the key selector
        /// functions.</typeparam>
        /// <typeparam name="TResult">The type of the result. This must match either
        /// TOuter or TInner</typeparam>
        /// <param name="outer">The first query to join.</param>
        /// <param name="inner">The query to join to the first query.</param>
        /// <param name="outerKeySelector">A function to extract a join key from the results of
        /// the first query.</param>
        /// <param name="innerKeySelector">A function to extract a join key from the results of
        /// the second query.</param>
        /// <param name="resultSelector">A function to select either the outer or inner query
        /// result to determine which query is the base query.</param>
        /// <returns>A new AVQuery with a WhereMatchesQuery or WhereMatchesKeyInQuery
        /// clause based upon the query indicated in the <paramref name="resultSelector"/>.</returns>
        public static AVQuery <TResult> Join <TOuter, TInner, TKey, TResult>(
            this AVQuery <TOuter> outer,
            AVQuery <TInner> inner,
            Expression <Func <TOuter, TKey> > outerKeySelector,
            Expression <Func <TInner, TKey> > innerKeySelector,
            Expression <Func <TOuter, TInner, TResult> > resultSelector)
            where TOuter : AVObject
            where TInner : AVObject
            where TResult : AVObject
        {
            // resultSelector must select either the inner object or the outer object. If it's the inner
            // object, reverse the query.
            if (resultSelector.Body == resultSelector.Parameters[1])
            {
                // The inner object was selected.
                return(inner.Join <TInner, TOuter, TKey, TInner>(
                           outer,
                           innerKeySelector,
                           outerKeySelector,
                           (i, o) => i) as AVQuery <TResult>);
            }
            if (resultSelector.Body != resultSelector.Parameters[0])
            {
                throw new InvalidOperationException("Joins must select either the outer or inner object.");
            }

            // Normalize both selectors
            Expression           outerNormalized = new ObjectNormalizer().Visit(outerKeySelector.Body);
            Expression           innerNormalized = new ObjectNormalizer().Visit(innerKeySelector.Body);
            MethodCallExpression outerAsGet      = outerNormalized as MethodCallExpression;
            MethodCallExpression innerAsGet      = innerNormalized as MethodCallExpression;

            if (IsParseObjectGet(outerAsGet) && outerAsGet.Object == outerKeySelector.Parameters[0])
            {
                var outerKey = GetValue(outerAsGet.Arguments[0]) as string;

                if (IsParseObjectGet(innerAsGet) && innerAsGet.Object == innerKeySelector.Parameters[0])
                {
                    // Both are key accesses, so treat this as a WhereMatchesKeyInQuery
                    var innerKey = GetValue(innerAsGet.Arguments[0]) as string;
                    return(outer.WhereMatchesKeyInQuery(outerKey, innerKey, inner) as AVQuery <TResult>);
                }

                if (innerKeySelector.Body == innerKeySelector.Parameters[0])
                {
                    // The inner selector is on the result of the query itself, so treat this as a
                    // WhereMatchesQuery
                    return(outer.WhereMatchesQuery(outerKey, inner) as AVQuery <TResult>);
                }
                throw new InvalidOperationException(
                          "The key for the joined object must be a AVObject or a field access " +
                          "on the AVObject.");
            }

            // TODO (hallucinogen): If we ever support "and" queries fully and/or support a "where this object
            // matches some key in some other query" (as opposed to requiring a key on this query), we
            // can add support for even more types of joins.

            throw new InvalidOperationException(
                      "The key for the selected object must be a field access on the AVObject.");
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Performs a subsequent ordering of a query based upon the key selector provided.
 /// </summary>
 /// <typeparam name="TSource">The type of AVObject being queried for.</typeparam>
 /// <typeparam name="TSelector">The type of key returned by keySelector.</typeparam>
 /// <param name="source">The query to order.</param>
 /// <param name="keySelector">A function to extract a key from the AVObject.</param>
 /// <returns>A new AVQuery based on Source whose results will be ordered by
 /// the key specified in the keySelector.</returns>
 public static AVQuery <TSource> ThenByDescending <TSource, TSelector>(
     this AVQuery <TSource> source, Expression <Func <TSource, TSelector> > keySelector)
     where TSource : AVObject
 {
     return(source.ThenByDescending(GetOrderByPath(keySelector)));
 }
Ejemplo n.º 16
0
        /// <summary>
        /// Converts a normalized method call expression into the appropriate AVQuery clause.
        /// </summary>
        private static AVQuery <T> WhereMethodCall <T>(
            this AVQuery <T> source, Expression <Func <T, bool> > expression, MethodCallExpression node)
            where T : AVObject
        {
            if (IsParseObjectGet(node) && (node.Type == typeof(bool) || node.Type == typeof(bool?)))
            {
                // This is a raw boolean field access like 'where obj.Get<bool>("foo")'
                return(source.WhereEqualTo(GetValue(node.Arguments[0]) as string, true));
            }

            MethodInfo translatedMethod;

            if (functionMappings.TryGetValue(node.Method, out translatedMethod))
            {
                var objTransformed = new ObjectNormalizer().Visit(node.Object) as MethodCallExpression;
                if (!(IsParseObjectGet(objTransformed) &&
                      objTransformed.Object == expression.Parameters[0]))
                {
                    throw new InvalidOperationException(
                              "The left-hand side of a supported function call must be a AVObject field access.");
                }
                var fieldPath   = GetValue(objTransformed.Arguments[0]);
                var containedIn = GetValue(node.Arguments[0]);
                var queryType   = translatedMethod.DeclaringType.GetGenericTypeDefinition()
                                  .MakeGenericType(typeof(T));
                translatedMethod = ReflectionHelpers.GetMethod(queryType,
                                                               translatedMethod.Name,
                                                               translatedMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                return(translatedMethod.Invoke(source, new[] { fieldPath, containedIn }) as AVQuery <T>);
            }

            if (node.Arguments[0] == expression.Parameters[0])
            {
                // obj.ContainsKey("foo") --> query.WhereExists("foo")
                if (node.Method == containsKeyMethod)
                {
                    return(source.WhereExists(GetValue(node.Arguments[1]) as string));
                }
                // !obj.ContainsKey("foo") --> query.WhereDoesNotExist("foo")
                if (node.Method == notContainsKeyMethod)
                {
                    return(source.WhereDoesNotExist(GetValue(node.Arguments[1]) as string));
                }
            }

            if (node.Method.IsGenericMethod)
            {
                if (node.Method.GetGenericMethodDefinition() == containsMethod)
                {
                    // obj.Get<IList<T>>("path").Contains(someValue)
                    if (IsParseObjectGet(node.Arguments[0] as MethodCallExpression))
                    {
                        return(source.WhereEqualTo(
                                   GetValue(((MethodCallExpression)node.Arguments[0]).Arguments[0]) as string,
                                   GetValue(node.Arguments[1])));
                    }
                    // someList.Contains(obj.Get<T>("path"))
                    if (IsParseObjectGet(node.Arguments[1] as MethodCallExpression))
                    {
                        var collection = GetValue(node.Arguments[0]) as System.Collections.IEnumerable;
                        return(source.WhereContainedIn(
                                   GetValue(((MethodCallExpression)node.Arguments[1]).Arguments[0]) as string,
                                   collection.Cast <object>()));
                    }
                }

                if (node.Method.GetGenericMethodDefinition() == notContainsMethod)
                {
                    // !obj.Get<IList<T>>("path").Contains(someValue)
                    if (IsParseObjectGet(node.Arguments[0] as MethodCallExpression))
                    {
                        return(source.WhereNotEqualTo(
                                   GetValue(((MethodCallExpression)node.Arguments[0]).Arguments[0]) as string,
                                   GetValue(node.Arguments[1])));
                    }
                    // !someList.Contains(obj.Get<T>("path"))
                    if (IsParseObjectGet(node.Arguments[1] as MethodCallExpression))
                    {
                        var collection = GetValue(node.Arguments[0]) as System.Collections.IEnumerable;
                        return(source.WhereNotContainedIn(
                                   GetValue(((MethodCallExpression)node.Arguments[1]).Arguments[0]) as string,
                                   collection.Cast <object>()));
                    }
                }
            }
            throw new InvalidOperationException(node.Method + " is not a supported method call in a where expression.");
        }