public static List <RqlNode> ExtractAggregates(RqlNode node)
        {
            if (node == null)
            {
                return(null);
            }

            var result = new List <RqlNode>();

            if (node.NodeType == RqlNodeType.AND)
            {
                foreach (var child in node.Value <List <RqlNode> >())
                {
                    result.AddRange(ExtractAggregates(child));
                }
            }
            else if (node.NodeType == RqlNodeType.OR)
            {
                foreach (var child in node.Value <List <RqlNode> >())
                {
                    result.AddRange(ExtractAggregates(child));
                }
            }
            else if (node.NodeType == RqlNodeType.SUM)
            {
                return(new List <RqlNode>()
                {
                    node
                });
            }
            else if (node.NodeType == RqlNodeType.MIN)
            {
                return(new List <RqlNode>()
                {
                    node
                });
            }
            else if (node.NodeType == RqlNodeType.MAX)
            {
                return(new List <RqlNode>()
                {
                    node
                });
            }
            else if (node.NodeType == RqlNodeType.MEAN)
            {
                return(new List <RqlNode>()
                {
                    node
                });
            }

            return(result);
        }
        /// <summary>
        /// Extract a Clause from the compiled RQL Query
        /// </summary>
        /// <param name="type"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static RqlNode ExtractClause(RqlNodeType type, RqlNode node)
        {
            if (node == null)
            {
                return(null);
            }

            if (node.NodeType == RqlNodeType.AND)
            {
                foreach (var child in node.Value <List <RqlNode> >())
                {
                    var clause = ExtractClause(type, child);

                    if (clause != null)
                    {
                        return(clause);
                    }
                }
            }
            else if (node.NodeType == RqlNodeType.OR)
            {
                foreach (var child in node.Value <List <RqlNode> >())
                {
                    var clause = ExtractClause(type, child);

                    if (clause != null)
                    {
                        return(clause);
                    }
                }
            }
            else if (node.NodeType == type)
            {
                return(node);
            }

            return(null);
        }
        /// <summary>
        /// Replaces a clause with a new one in place
        /// </summary>
        /// <param name="type"></param>
        /// <param name="node"></param>
        /// <param name="replacement"></param>
        /// <returns></returns>
        public static RqlNode ReplaceClause(RqlNodeType type, RqlNode node, RqlNode replacement)
        {
            if (node.NodeType == RqlNodeType.AND)
            {
                for (int i = 0; i < node.Value <List <RqlNode> >().Count; i++)
                {
                    node.SetValue <RqlNode>(i, ReplaceClause(type, node.Value <RqlNode>(i), replacement));
                }
            }
            else if (node.NodeType == RqlNodeType.OR)
            {
                for (int i = 0; i < node.Value <List <RqlNode> >().Count; i++)
                {
                    node.SetValue <RqlNode>(i, ReplaceClause(type, node.Value <RqlNode>(i), replacement));
                }
            }
            else if (node.NodeType == type)
            {
                return(replacement);
            }

            return(node);
        }
        /// <summary>
        /// Gets a collection
        /// </summary>
        /// <param name="T">The type of items to retrieve</param>
        /// <param name="keys">The list of keys to further limit the results of the query.</param>
        /// <param name="node">The compiled RQL Query</param>
        /// <param name="NoPaging">Do not page results even if the result set exceeds the system defined limit. Default value = false.</param>
        /// <returns></returns>
        public async Task <object> GetCollectionAsync(Type T, IEnumerable <KeyValuePair <string, object> > keys, RqlNode node, bool NoPaging)
        {
            using (var ctc = new CancellationTokenSource())
            {
                var task = Task.Run(async() =>
                {
                    var parameters         = new List <SqlParameter>();
                    var pageFilter         = RqlUtilities.ExtractClause(RqlNodeType.LIMIT, node);
                    var options            = ServiceProvider.GetService <IRepositoryOptions>();
                    var translationOptions = ServiceProvider.GetService <ITranslationOptions>();
                    var emitter            = new Emitter(ServiceProvider);

                    var rdgeneric  = typeof(List <>);
                    var rd         = rdgeneric.MakeGenericType(T);
                    var resultList = Activator.CreateInstance(rd);

                    var rxgeneric        = typeof(RqlCollection <>);
                    var rx               = rxgeneric.MakeGenericType(T);
                    var results          = Activator.CreateInstance(rx);
                    var countProperty    = results.GetType().GetProperty("count");
                    var itemsProperty    = results.GetType().GetProperty("items");
                    var limitProperty    = results.GetType().GetProperty("limit");
                    var hrefProperty     = results.GetType().GetProperty("href");
                    var firstProperty    = results.GetType().GetProperty("first");
                    var previousProperty = results.GetType().GetProperty("previous");
                    var nextProperty     = results.GetType().GetProperty("next");

                    if (!NoPaging)
                    {
                        if (pageFilter != null && pageFilter.Value <int>(0) < 1)
                        {
                            pageFilter = new RqlNode(RqlNodeType.LIMIT, new List <int> {
                                1, options.BatchLimit
                            });
                        }
                        else
                        {
                            var sqlCount = emitter.BuildCollectionCountQuery(keys, node, parameters, T);
                            Logger.BeginScope <string>(sqlCount.ToString());
                            Logger.LogTrace($"[REPOSITORY] ReadCollection<{T.Name}>");

                            //	We now have an SQL query that needs to be executed in order to get our object.
                            using (var command = new SqlCommand(sqlCount, _connection))
                            {
                                foreach (var parameter in parameters)
                                {
                                    command.Parameters.Add(parameter);
                                }

                                using (var reader = await command.ExecuteReaderAsync(ctc.Token))
                                {
                                    if (await reader.ReadAsync())
                                    {
                                        countProperty.SetValue(results, await reader.ReadInt32Async("RecordCount", ctc.Token));
                                    }
                                }
                            }
                        }

                        if (ctc.Token.IsCancellationRequested)
                        {
                            return(default);
 /// <summary>
 /// Gets a collection
 /// </summary>
 /// <param name="T">The type of items to retrieve</param>
 /// <param name="node">The compiled RQL Query</param>
 /// <param name="NoPaging">Do not page results even if the result set exceeds the system defined limit. Default value = false.</param>
 /// <returns></returns>
 public async Task <object> GetCollectionAsync(Type T, RqlNode node, bool NoPaging)
 {
     return(await GetCollectionAsync(T, new List <KeyValuePair <string, object> >(), node, NoPaging));
 }