/// <summary>
        ///     Populates into the supplied list all aggregation functions within this expression, if any.
        ///     <para />
        ///     Populates by going bottom-up such that nested aggregates appear first.
        ///     <para />
        ///     I.e. sum(volume * sum(price)) would put first A then B into the list with A=sum(price) and B=sum(volume * A)
        /// </summary>
        /// <param name="topNode">is the expression node to deep inspect</param>
        /// <param name="aggregateNodes">is a list of node to populate into</param>
        public static void GetAggregatesBottomUp(
            ExprNode topNode,
            IList<ExprAggregateNode> aggregateNodes)
        {
            // Map to hold per level of the node (1 to N depth) of expression node a list of aggregation expr nodes, if any
            // exist at that level
            var aggregateExprPerLevel = new OrderedListDictionary<int, IList<ExprAggregateNode>>();

            RecursiveAggregate(topNode, aggregateExprPerLevel, 1);

            // Done if none found
            if (aggregateExprPerLevel.IsEmpty()) {
                return;
            }

            // From the deepest (highest) level to the lowest, add aggregates to list
            int deepLevel = aggregateExprPerLevel.Last().Key;
            for (var i = deepLevel; i >= 1; i--) {
                var list = aggregateExprPerLevel.Get(i);
                if (list == null) {
                    continue;
                }

                aggregateNodes.AddAll(list);
            }
        }
            public void Run(RegressionEnvironment env)
            {
                var epl = "create table MyTable(sortcol sorted(IntPrimitive) @type('SupportBean'));\n" +
                          "into table MyTable select sorted(*) as sortcol from SupportBean;\n" +
                          "@Name('s0') select " +
                          "MyTable.sortcol.firstEvent() as fe," +
                          "MyTable.sortcol.minBy() as minb," +
                          "MyTable.sortcol.firstEvents() as fes," +
                          "MyTable.sortcol.firstKey() as fk," +
                          "MyTable.sortcol.lastEvent() as le," +
                          "MyTable.sortcol.maxBy() as maxb," +
                          "MyTable.sortcol.lastEvents() as les," +
                          "MyTable.sortcol.lastKey() as lk" +
                          " from SupportBean_S0";

                env.CompileDeploy(epl).AddListener("s0");

                AssertType(env, typeof(SupportBean), "fe,le,minb,maxb");
                AssertType(env, typeof(SupportBean[]), "fes,les");
                AssertType(env, typeof(int?), "fk,lk");

                var treemap = new OrderedListDictionary <int, IList <SupportBean> >();

                PrepareTestData(env, treemap);                 // 1, 1, 4, 6, 6, 8, 9

                var treeMapFirst = treemap.First();
                var treeMapLast  = treemap.Last();

                env.SendEventBean(new SupportBean_S0(-1));
                var @event = env.Listener("s0").AssertOneGetNewAndReset();

                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapFirst), @event.Get("fe"));
                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapFirst), @event.Get("minb"));
                EPAssertionUtil.AssertEqualsExactOrder(AllEvents <IList <SupportBean> >(treeMapFirst), (SupportBean[])@event.Get("fes"));
                Assert.AreEqual(treeMapFirst.Key, @event.Get("fk"));
                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapLast), @event.Get("le"));
                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapLast), @event.Get("maxb"));
                EPAssertionUtil.AssertEqualsExactOrder(AllEvents <IList <SupportBean> >(treeMapLast), (SupportBean[])@event.Get("les"));
                Assert.AreEqual(treeMapLast.Key, @event.Get("lk"));

                env.UndeployAll();
            }
            public void Run(RegressionEnvironment env)
            {
                var epl = "create table MyTable(sortcol sorted(IntPrimitive) @type('SupportBean'));\n" +
                          "into table MyTable select sorted(*) as sortcol from SupportBean;\n" +
                          "@Name('s0') select " +
                          "MyTable.sortcol.firstEvent().TheString as feid," +
                          "MyTable.sortcol.firstEvent().firstOf() as fefo," +
                          "MyTable.sortcol.firstEvents().lastOf() as feslo," +
                          "MyTable.sortcol.lastEvent().TheString() as leid," +
                          "MyTable.sortcol.lastEvent().firstOf() as lefo," +
                          "MyTable.sortcol.lastEvents().lastOf as leslo" +
                          " from SupportBean_S0";

                env.CompileDeploy(epl).AddListener("s0");

                AssertType(env, typeof(string), "feid,leid");
                AssertType(env, typeof(SupportBean), "fefo,feslo,lefo,leslo");

                var treemap = new OrderedListDictionary <int, IList <SupportBean> >();

                PrepareTestData(env, treemap);                 // 1, 1, 4, 6, 6, 8, 9
                var treeMapFirst = treemap.First();
                var treeMapLast  = treemap.Last();

                env.SendEventBean(new SupportBean_S0(-1));
                var @event = env.Listener("s0").AssertOneGetNewAndReset();

                Assert.AreEqual(FirstEventString <IList <SupportBean> >(treeMapFirst), @event.Get("feid"));
                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapFirst), @event.Get("fefo"));
                Assert.AreEqual(LastEvent <IList <SupportBean> >(treeMapFirst), @event.Get("feslo"));
                Assert.AreEqual(FirstEventString <IList <SupportBean> >(treeMapLast), @event.Get("leid"));
                Assert.AreEqual(FirstEvent <IList <SupportBean> >(treeMapLast), @event.Get("lefo"));
                Assert.AreEqual(LastEvent <IList <SupportBean> >(treeMapLast), @event.Get("leslo"));

                env.UndeployAll();
            }