Jelajahi Sumber

Fixed incapability of the aggregate system to compose Count aggregates.

Kenric Nugteren 10 bulan lalu
induk
melakukan
3bb5d8763b
2 mengubah file dengan 113 tambahan dan 65 penghapusan
  1. 96 42
      InABox.Core/Aggregate.cs
  2. 17 23
      inabox.database.sqlite/SQLiteProvider.cs

+ 96 - 42
InABox.Core/Aggregate.cs

@@ -151,9 +151,19 @@ namespace InABox.Core
         Dictionary<string, string> GetLinks();
     }
 
-    public class ComplexFormulaAggregateNode<TType, TAggregate, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaAggregateNode
+    /// <summary>
+    /// Represents an aggregate, to form a single value from another table in the database.
+    /// </summary>
+    /// <typeparam name="TType">The type of the parent table, on which this formula is defined.</typeparam>
+    /// <typeparam name="TAggregate">The type of the child table, which is being aggregated.</typeparam>
+    /// <typeparam name="TExpression">The type of the property which is being aggregated.</typeparam>
+    /// <typeparam name="TResult">
+    ///     The type of the result of the aggregate. In most cases, this will be the same as <typeparamref name="TExpression"/>,
+    ///     except for aggregates like <see cref="AggregateCalculation.Count"/>, which will always be <see cref="int"/>.
+    /// </typeparam>
+    public class ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaAggregateNode
     {
-        public IComplexFormulaNode<TAggregate, TResult> Expression { get; set; }
+        public IComplexFormulaNode<TAggregate, TExpression> Expression { get; set; }
 
         public AggregateCalculation Calculation { get; set; }
 
@@ -165,7 +175,7 @@ namespace InABox.Core
 
         Type IComplexFormulaAggregateNode.TResult => typeof(TResult);
 
-        public ComplexFormulaAggregateNode(IComplexFormulaNode<TAggregate, TResult> expression, AggregateCalculation calculation, Filter<TAggregate>? filter, Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> links)
+        public ComplexFormulaAggregateNode(IComplexFormulaNode<TAggregate, TExpression> expression, AggregateCalculation calculation, Filter<TAggregate>? filter, Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> links)
         {
             Expression = expression;
             Calculation = calculation;
@@ -173,18 +183,18 @@ namespace InABox.Core
             Links = links;
         }
 
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithFilter(Filter<TAggregate> filter)
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithFilter(Filter<TAggregate> filter)
         {
             Filter = filter;
             return this;
         }
 
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLink(Expression<Func<TAggregate, object?>> aggLink, Expression<Func<TType, object?>> masterLink)
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLink(Expression<Func<TAggregate, object?>> aggLink, Expression<Func<TType, object?>> masterLink)
         {
             Links.Add(aggLink, masterLink);
             return this;
         }
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLinks(
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLinks(
             IEnumerable<KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>> links)
         {
             Links.AddRange(links);
@@ -223,48 +233,48 @@ namespace InABox.Core
     /// <typeparam name="TType"></typeparam>
     /// <typeparam name="TAggregate"></typeparam>
     /// <typeparam name="TResult"></typeparam>
-    public class ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult>
+    public class ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, TResult>
     {
-        public IComplexFormulaNode<TAggregate, TResult> Expression { get; set; }
+        public IComplexFormulaNode<TAggregate, TExpression> Expression { get; set; }
 
         public AggregateCalculation Calculation { get; set; }
 
         public Filter<TAggregate>? Filter { get; set; }
 
-        public ComplexFormulaPartialAggregateNode(IComplexFormulaNode<TAggregate, TResult> expression, AggregateCalculation calculation, Filter<TAggregate>? filter)
+        public ComplexFormulaPartialAggregateNode(IComplexFormulaNode<TAggregate, TExpression> expression, AggregateCalculation calculation, Filter<TAggregate>? filter)
         {
             Expression = expression;
             Calculation = calculation;
             Filter = filter;
         }
 
-        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> WithFilter(Filter<TAggregate> filter)
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, TResult> WithFilter(Filter<TAggregate> filter)
         {
             Filter = filter;
             return this;
         }
 
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLink(Expression<Func<TAggregate, object?>> aggLink, Expression<Func<TType, object?>> masterLink)
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLink(Expression<Func<TAggregate, object?>> aggLink, Expression<Func<TType, object?>> masterLink)
         {
-            var node = new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(Expression, Calculation, Filter, new Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>());
+            var node = new ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult>(Expression, Calculation, Filter, new Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>());
             node.Links.Add(aggLink, masterLink);
             return node;
         }
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLinks(
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLinks(
             IEnumerable<KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>> links)
         {
-            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(Expression, Calculation, Filter,
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult>(Expression, Calculation, Filter,
                 new Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>().AddRange(links));
         }
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLinks(
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLinks(
             Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> links)
         {
-            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(Expression, Calculation, Filter, links);
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult>(Expression, Calculation, Filter, links);
         }
-        public ComplexFormulaAggregateNode<TType, TAggregate, TResult> WithLinks(
+        public ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult> WithLinks(
             params KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links)
         {
-            var node = new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(Expression, Calculation, Filter, new Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>());
+            var node = new ComplexFormulaAggregateNode<TType, TAggregate, TExpression, TResult>(Expression, Calculation, Filter, new Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>());
             node.Links.AddRange(links);
             return node;
         }
@@ -422,16 +432,32 @@ namespace InABox.Core
             Filter<TAggregate>? filter = null
         )
         {
-            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(expression, calculation, filter, links.ToDictionary(x => x.Key, x => x.Value));
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult, TResult>(expression, calculation, filter, links.ToDictionary(x => x.Key, x => x.Value));
         }
 
-        public static ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TType, TAggregate, TResult>(
+        public static ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult, TResult> Aggregate<TType, TAggregate, TResult>(
             AggregateCalculation calculation,
             IComplexFormulaNode<TAggregate, TResult> expression,
             Filter<TAggregate>? filter = null
         )
         {
-            return new ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult>(expression, calculation, filter);
+            return new ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult, TResult>(expression, calculation, filter);
+        }
+
+        public static IComplexFormulaNode<TType, int> Count<TType, TAggregate, TExpression>(
+            IComplexFormulaNode<TAggregate, TExpression> expression,
+            KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
+            Filter<TAggregate>? filter = null)
+        {
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TExpression, int>(expression, AggregateCalculation.Count, filter, links.ToDictionary(x => x.Key, x => x.Value));
+        }
+
+        public static ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, int> Count<TType, TAggregate, TExpression>(
+            IComplexFormulaNode<TAggregate, TExpression> expression,
+            Filter<TAggregate>? filter = null
+        )
+        {
+            return new ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, int>(expression, AggregateCalculation.Count, filter);
         }
 
         public static IComplexFormulaNode<TType, TResult> Constant<TType, TResult>(TResult constant)
@@ -454,19 +480,27 @@ namespace InABox.Core
 
         IComplexFormulaNode<TType, TResult> Formula(FormulaOperator op, params IComplexFormulaNode<TType, TResult>[] operands);
 
+        IComplexFormulaNode<TType, TResult> Constant(TResult constant);
+
         IComplexFormulaNode<TType, TResult> Aggregate<TAggregate>(
             AggregateCalculation calculation,
             Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
             KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
             Filter<TAggregate>? filter = null);
 
-        IComplexFormulaNode<TType, TResult> Constant(TResult constant);
-
-        ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TAggregate>(
+        ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult, TResult> Aggregate<TAggregate>(
             AggregateCalculation calculation,
             Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
-            Filter<TAggregate>? filter = null
-        );
+            Filter<TAggregate>? filter = null);
+
+        IComplexFormulaNode<TType, int> Count<TAggregate, TExpression>(
+            Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression,
+            KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
+            Filter<TAggregate>? filter = null);
+
+        ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, int> Count<TAggregate, TExpression>(
+            Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression,
+            Filter<TAggregate>? filter = null);
 
         ComplexFormulaPartial0ConditionNode<TType, TCondition, TResult> If<TCondition>(
             Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> left,
@@ -486,6 +520,11 @@ namespace InABox.Core
             return ComplexFormulaGenerator.Formula(op, operands);
         }
 
+        public IComplexFormulaNode<TType, TResult> Constant(TResult constant)
+        {
+            return ComplexFormulaGenerator.Constant<TType, TResult>(constant);
+        }
+
         public IComplexFormulaNode<TType, TResult> Aggregate<TAggregate>(
             AggregateCalculation calculation,
             Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
@@ -495,12 +534,7 @@ namespace InABox.Core
             return ComplexFormulaGenerator.Aggregate(calculation, expression(new InternalComplexFormulaGenerator<TAggregate, TResult>()), links, filter);
         }
 
-        public IComplexFormulaNode<TType, TResult> Constant(TResult constant)
-        {
-            return ComplexFormulaGenerator.Constant<TType, TResult>(constant);
-        }
-
-        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TAggregate>(
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult, TResult> Aggregate<TAggregate>(
             AggregateCalculation calculation,
             Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
             Filter<TAggregate>? filter = null)
@@ -519,6 +553,16 @@ namespace InABox.Core
                 condition,
                 right(generator));
         }
+
+        public IComplexFormulaNode<TType, int> Count<TAggregate, TExpression>(Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression, KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links, Filter<TAggregate>? filter = null)
+        {
+            return ComplexFormulaGenerator.Count(expression(new InternalComplexFormulaGenerator<TAggregate, TExpression>()), links, filter);
+        }
+
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, int> Count<TAggregate, TExpression>(Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression, Filter<TAggregate>? filter = null)
+        {
+            return ComplexFormulaGenerator.Count<TType, TAggregate, TExpression>(expression(new InternalComplexFormulaGenerator<TAggregate, TExpression>()), filter);
+        }
     }
 
     public abstract class ComplexFormulaGenerator<TType, TResult> : ComplexFormulaGenerator, IComplexFormulaGenerator<TType, TResult>, IComplexFormulaGenerator
@@ -531,15 +575,6 @@ namespace InABox.Core
 
         private readonly InternalComplexFormulaGenerator<TType, TResult> InternalGenerator = new InternalComplexFormulaGenerator<TType, TResult>();
 
-        public IComplexFormulaNode<TType, TResult> Aggregate<TAggregate>(
-            AggregateCalculation calculation,
-            Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
-            KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
-            Filter<TAggregate>? filter = null)
-        {
-            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Aggregate(calculation, expression, links, filter);
-        }
-
         public IComplexFormulaNode<TType, TResult> Formula(FormulaOperator op, params IComplexFormulaNode<TType, TResult>[] operands)
         {
             return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Formula(op, operands);
@@ -555,7 +590,16 @@ namespace InABox.Core
             return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Constant(constant);
         }
 
-        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TAggregate>(
+        public IComplexFormulaNode<TType, TResult> Aggregate<TAggregate>(
+            AggregateCalculation calculation,
+            Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
+            KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
+            Filter<TAggregate>? filter = null)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Aggregate(calculation, expression, links, filter);
+        }
+
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult, TResult> Aggregate<TAggregate>(
             AggregateCalculation calculation,
             Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
             Filter<TAggregate>? filter = null)
@@ -568,6 +612,16 @@ namespace InABox.Core
             return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).If(left, condition, right);
         }
 
+        public IComplexFormulaNode<TType, int> Count<TAggregate, TExpression>(Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression, KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links, Filter<TAggregate>? filter = null)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Count(expression, links, filter);
+        }
+
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TExpression, int> Count<TAggregate, TExpression>(Func<IComplexFormulaGenerator<TAggregate, TExpression>, IComplexFormulaNode<TAggregate, TExpression>> expression, Filter<TAggregate>? filter = null)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Count(expression, filter);
+        }
+
         #endregion
     }
 

+ 17 - 23
inabox.database.sqlite/SQLiteProvider.cs

@@ -1533,32 +1533,26 @@ public class SQLiteProvider : IProvider
         CoreTable? _result = null;
         try
         {
-            using (var access = GetReadAccess())
-            {
-                using (var command = access.CreateCommand())
-                {
-                    command.CommandText = $"select * from {name}";
-                    using (var reader = command.ExecuteReader())
-                    { 
-                        _result = new CoreTable();
-                        var schema = reader.GetColumnSchema();
-                        foreach (var column in schema)
-                            _result.Columns.Add(new CoreColumn(column.DataType, column.ColumnName));
-                        
+            using var access = GetReadAccess();
+            using var command = access.CreateCommand();
+            command.CommandText = $"select * from {name}";
+            using var reader = command.ExecuteReader();
+            _result = new CoreTable();
+            var schema = reader.GetColumnSchema();
+            foreach (var column in schema)
+                _result.Columns.Add(new CoreColumn(column.DataType, column.ColumnName));
 
-                        var _colCount = reader.GetColumnSchema().Count;
 
-                        while (reader.Read())
-                        {
-                            var _row = _result.NewRow();
-                            for (int i=0; i <_colCount; i++)
-                                ReadAndDecodeValue(_result,reader,_row,i);
-                            _result.Rows.Add(_row);
-                        }
-                        reader.Close();
-                    }
-                }
+            var _colCount = reader.GetColumnSchema().Count;
+
+            while (reader.Read())
+            {
+                var _row = _result.NewRow();
+                for (int i = 0; i < _colCount; i++)
+                    ReadAndDecodeValue(_result, reader, _row, i);
+                _result.Rows.Add(_row);
             }
+            reader.Close();
         }
         catch (Exception e)
         {