Browse Source

Added ComplexFormula

Kenric Nugteren 10 tháng trước cách đây
mục cha
commit
48774707a6
3 tập tin đã thay đổi với 2165 bổ sung1496 xóa
  1. 512 0
      InABox.Core/Aggregate.cs
  2. 50 2
      InABox.Core/Query/Column.cs
  3. 1603 1494
      inabox.database.sqlite/SQLiteProvider.cs

+ 512 - 0
InABox.Core/Aggregate.cs

@@ -61,6 +61,518 @@ namespace InABox.Core
         }
     }
 
+    #region ComplexFormula
+
+    public static class ComplexFormula
+    {
+        public static IComplexFormulaFieldNode Field(Type T, Type TResult, string field)
+        {
+            var type = typeof(ComplexFormulaFieldNode<,>).MakeGenericType(T, TResult);
+            return (Activator.CreateInstance(type, field) as IComplexFormulaFieldNode)!;
+        }
+    }
+
+    public interface IComplexFormulaNode
+    {
+        Type TType { get; }
+
+        IComplexColumn ToColumn(string columnName);
+    }
+
+    public interface IComplexFormulaNode<TType, TResult> : IComplexFormulaNode
+    {
+        Type IComplexFormulaNode.TType => typeof(TType);
+
+        IComplexColumn IComplexFormulaNode.ToColumn(string columnName) => new ComplexColumn<TType, TResult>(columnName, this);
+    }
+
+    #region FieldNode
+
+    public interface IComplexFormulaFieldNode : IComplexFormulaNode
+    {
+        string GetField();
+    }
+
+    public class ComplexFormulaFieldNode<TType, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaFieldNode
+    {
+        //public Expression<Func<TType, TResult>> Expression { get; set; }
+        public string Field { get; set; }
+
+        public ComplexFormulaFieldNode(Expression<Func<TType, TResult>> expression)
+        {
+            Field = CoreUtils.GetFullPropertyName(expression, ".");
+        }
+
+        internal ComplexFormulaFieldNode(string field)
+        {
+            Field = field;
+        }
+
+        string IComplexFormulaFieldNode.GetField() => Field;
+    }
+
+    #endregion
+
+    #region ConstantNode
+
+    public interface IComplexFormulaConstantNode : IComplexFormulaNode
+    {
+        object? GetConstant();
+    }
+
+    public class ComplexFormulaConstantNode<TType, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaConstantNode
+    {
+        public TResult Constant { get; set; }
+
+        public ComplexFormulaConstantNode(TResult constant)
+        {
+            Constant = constant;
+        }
+
+        object? IComplexFormulaConstantNode.GetConstant() => Constant;
+    }
+
+    #endregion
+
+    #region AggregateNode
+
+    public interface IComplexFormulaAggregateNode : IComplexFormulaNode
+    {
+        Type TAggregate { get; }
+
+        IComplexFormulaNode GetExpression();
+
+        AggregateCalculation GetCalculation();
+
+        IFilter? GetFilter();
+
+        Dictionary<string, string> GetLinks();
+    }
+
+    public class ComplexFormulaAggregateNode<TType, TAggregate, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaAggregateNode
+    {
+        public IComplexFormulaNode<TAggregate, TResult> Expression { get; set; }
+
+        public AggregateCalculation Calculation { get; set; }
+
+        public Filter<TAggregate>? Filter { get; set; }
+
+        public Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> Links { get; }
+
+        Type IComplexFormulaAggregateNode.TAggregate => typeof(TAggregate);
+
+        public ComplexFormulaAggregateNode(IComplexFormulaNode<TAggregate, TResult> expression, AggregateCalculation calculation, Filter<TAggregate>? filter, Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> links)
+        {
+            Expression = expression;
+            Calculation = calculation;
+            Filter = filter;
+            Links = links;
+        }
+
+        public ComplexFormulaAggregateNode<TType, TAggregate, 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)
+        {
+            Links.Add(aggLink, masterLink);
+            return this;
+        }
+
+        #region IComplexFormulaAggregateNode
+
+        IComplexFormulaNode IComplexFormulaAggregateNode.GetExpression()
+        {
+            return Expression;
+        }
+
+        AggregateCalculation IComplexFormulaAggregateNode.GetCalculation()
+        {
+            return Calculation;
+        }
+
+        IFilter? IComplexFormulaAggregateNode.GetFilter()
+        {
+            return Filter;
+        }
+
+        Dictionary<string, string> IComplexFormulaAggregateNode.GetLinks()
+        {
+            return Links.ToDictionary(x => CoreUtils.GetFullPropertyName(x.Key, "."), x => CoreUtils.GetFullPropertyName(x.Value, "."));
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// Represents an aggregate that has no links set; call <see cref="WithLink(Expression{Func{TAggregate, object?}}, Expression{Func{TType, object?}})"/> to 
+    /// set the link.
+    /// </summary>
+    /// <typeparam name="TType"></typeparam>
+    /// <typeparam name="TAggregate"></typeparam>
+    /// <typeparam name="TResult"></typeparam>
+    public class ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult>
+    {
+        public IComplexFormulaNode<TAggregate, TResult> 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)
+        {
+            Expression = expression;
+            Calculation = calculation;
+            Filter = filter;
+        }
+
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, 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)
+        {
+            var node = new ComplexFormulaAggregateNode<TType, TAggregate, 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(
+            Dictionary<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>> links)
+        {
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(Expression, Calculation, Filter, links);
+        }
+        public ComplexFormulaAggregateNode<TType, TAggregate, 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?>>>());
+            node.Links.AddRange(links);
+            return node;
+        }
+    }
+
+    #endregion
+
+    #region FormulaNode
+
+    public interface IComplexFormulaFormulaNode : IComplexFormulaNode
+    {
+        IEnumerable<IComplexFormulaNode> GetOperands();
+
+        FormulaOperator GetOperator();
+    }
+    public class ComplexFormulaFormulaNode<TType, TResult> : IComplexFormulaNode<TType, TResult>, IComplexFormulaFormulaNode
+    {
+        public IComplexFormulaNode<TType, TResult>[] Operands { get; set; }
+
+        public FormulaOperator Operator { get; set; }
+
+        public ComplexFormulaFormulaNode(IComplexFormulaNode<TType, TResult>[] operands, FormulaOperator op)
+        {
+            Operands = operands;
+            Operator = op;
+        }
+
+        IEnumerable<IComplexFormulaNode> IComplexFormulaFormulaNode.GetOperands() => Operands;
+
+        FormulaOperator IComplexFormulaFormulaNode.GetOperator() => Operator;
+    }
+
+    #endregion
+
+    #region ConditionNode
+
+    public class ComplexFormulaPartial0ConditionNode<TType, TCondition, TValue>
+    {
+        public IComplexFormulaNode<TType, TCondition> Left { get; set; }
+
+        public IComplexFormulaNode<TType, TCondition> Right { get; set; }
+
+        public Condition Condition { get; set; }
+
+        public ComplexFormulaPartial0ConditionNode(IComplexFormulaNode<TType, TCondition> left, IComplexFormulaNode<TType, TCondition> right, Condition condition)
+        {
+            Left = left;
+            Right = right;
+            Condition = condition;
+        }
+
+        public ComplexFormulaPartial1ConditionNode<TType, TCondition, TValue> Then(IComplexFormulaNode<TType, TValue> then)
+        {
+            return new ComplexFormulaPartial1ConditionNode<TType, TCondition, TValue>(Left, Right, Condition, then);
+        }
+    }
+
+    public class ComplexFormulaPartial1ConditionNode<TType, TCondition, TValue>
+    {
+        public IComplexFormulaNode<TType, TCondition> Left { get; set; }
+
+        public IComplexFormulaNode<TType, TCondition> Right { get; set; }
+
+        public IComplexFormulaNode<TType, TValue> True { get; set; }
+
+        public Condition Condition { get; set; }
+
+        public ComplexFormulaPartial1ConditionNode(IComplexFormulaNode<TType, TCondition> left, IComplexFormulaNode<TType, TCondition> right, Condition condition, IComplexFormulaNode<TType, TValue> trueValue)
+        {
+            Left = left;
+            Right = right;
+            Condition = condition;
+            True = trueValue;
+        }
+
+        public ComplexFormulaConditionNode<TType, TCondition, TValue> Else(IComplexFormulaNode<TType, TValue> elseValue)
+        {
+            return new ComplexFormulaConditionNode<TType, TCondition, TValue>(Left, Right, True, elseValue, Condition);
+        }
+    }
+
+    public interface IComplexFormulaConditionNode : IComplexFormulaNode
+    {
+        public Type TCondition { get; }
+
+        public IComplexFormulaNode Left { get; }
+
+        public IComplexFormulaNode Right { get; }
+
+        public IComplexFormulaNode True { get; }
+
+        public IComplexFormulaNode False { get; }
+
+        public Condition Condition { get; }
+    }
+    public class ComplexFormulaConditionNode<TType, TCondition, TValue> : IComplexFormulaNode<TType, TValue>, IComplexFormulaConditionNode
+    {
+        Type IComplexFormulaConditionNode.TCondition => typeof(TCondition);
+
+        public IComplexFormulaNode<TType, TCondition> Left { get; set; }
+
+        public IComplexFormulaNode<TType, TCondition> Right { get; set; }
+
+        public IComplexFormulaNode<TType, TValue> True { get; set; }
+
+        public IComplexFormulaNode<TType, TValue> False { get; set; }
+
+        public Condition Condition { get; set; }
+
+        public ComplexFormulaConditionNode(IComplexFormulaNode<TType, TCondition> left, IComplexFormulaNode<TType, TCondition> right, IComplexFormulaNode<TType, TValue> trueValue, IComplexFormulaNode<TType, TValue> falseValue, Condition condition)
+        {
+            Left = left;
+            Right = right;
+            True = trueValue;
+            False = falseValue;
+            Condition = condition;
+        }
+
+        IComplexFormulaNode IComplexFormulaConditionNode.Left => Left;
+        IComplexFormulaNode IComplexFormulaConditionNode.Right => Right;
+        IComplexFormulaNode IComplexFormulaConditionNode.True => True;
+        IComplexFormulaNode IComplexFormulaConditionNode.False => False;
+
+    }
+
+    #endregion
+
+    #region Generator + Interface
+
+    public interface IComplexFormulaGenerator
+    {
+        IComplexFormulaNode GetFormula();
+    }
+
+    public abstract class ComplexFormulaGenerator
+    {
+        public static IComplexFormulaNode<TType, TResult> Property<TType, TResult>(Expression<Func<TType, TResult>> expression)
+        {
+            return new ComplexFormulaFieldNode<TType, TResult>(expression);
+        }
+
+        public static IComplexFormulaNode<TType, TResult> Formula<TType, TResult>(FormulaOperator op, params IComplexFormulaNode<TType, TResult>[] operands)
+        {
+            return new ComplexFormulaFormulaNode<TType, TResult>(operands, op);
+        }
+
+        public static IComplexFormulaNode<TType, TResult> Aggregate<TType, TAggregate, TResult>(
+            AggregateCalculation calculation,
+            IComplexFormulaNode<TAggregate, TResult> expression,
+            KeyValuePair<Expression<Func<TAggregate, object?>>, Expression<Func<TType, object?>>>[] links,
+            Filter<TAggregate>? filter = null
+        )
+        {
+            return new ComplexFormulaAggregateNode<TType, TAggregate, TResult>(expression, calculation, filter, links.ToDictionary(x => x.Key, x => x.Value));
+        }
+
+        public static ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TType, TAggregate, TResult>(
+            AggregateCalculation calculation,
+            IComplexFormulaNode<TAggregate, TResult> expression,
+            Filter<TAggregate>? filter = null
+        )
+        {
+            return new ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult>(expression, calculation, filter);
+        }
+
+        public static IComplexFormulaNode<TType, TResult> Constant<TType, TResult>(TResult constant)
+        {
+            return new ComplexFormulaConstantNode<TType, TResult>(constant);
+        }
+
+        public static ComplexFormulaPartial0ConditionNode<TType, TCondition, TValue> If<TType, TCondition, TValue>(
+            IComplexFormulaNode<TType, TCondition> left,
+            Condition condition,
+            IComplexFormulaNode<TType, TCondition> right)
+        {
+            return new ComplexFormulaPartial0ConditionNode<TType, TCondition, TValue>(left, right, condition);
+        }
+    }
+
+    public interface IComplexFormulaGenerator<TType, TResult>
+    {
+        IComplexFormulaNode<TType, TResult> Property(Expression<Func<TType, TResult>> epxression);
+
+        IComplexFormulaNode<TType, TResult> Formula(FormulaOperator op, params IComplexFormulaNode<TType, TResult>[] operands);
+
+        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>(
+            AggregateCalculation calculation,
+            Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
+            Filter<TAggregate>? filter = null
+        );
+
+        ComplexFormulaPartial0ConditionNode<TType, TCondition, TResult> If<TCondition>(
+            Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> left,
+            Condition condition,
+            Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> right);
+    }
+
+    internal class InternalComplexFormulaGenerator<TType, TResult> : IComplexFormulaGenerator<TType, TResult>
+    {
+        public IComplexFormulaNode<TType, TResult> Property(Expression<Func<TType, TResult>> expression)
+        {
+            return ComplexFormulaGenerator.Property(expression);
+        }
+
+        public IComplexFormulaNode<TType, TResult> Formula(FormulaOperator op, params IComplexFormulaNode<TType, TResult>[] operands)
+        {
+            return ComplexFormulaGenerator.Formula(op, operands);
+        }
+
+        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 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>(
+            AggregateCalculation calculation,
+            Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
+            Filter<TAggregate>? filter = null)
+        {
+            return ComplexFormulaGenerator.Aggregate<TType, TAggregate, TResult>(calculation, expression(new InternalComplexFormulaGenerator<TAggregate, TResult>()), filter);
+        }
+
+        public ComplexFormulaPartial0ConditionNode<TType, TCondition, TResult> If<TCondition>(
+            Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> left,
+            Condition condition,
+            Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> right)
+        {
+            var generator = new InternalComplexFormulaGenerator<TType, TCondition>();
+            return ComplexFormulaGenerator.If<TType, TCondition, TResult>(
+                left(generator),
+                condition,
+                right(generator));
+        }
+    }
+
+    public abstract class ComplexFormulaGenerator<TType, TResult> : ComplexFormulaGenerator, IComplexFormulaGenerator<TType, TResult>, IComplexFormulaGenerator
+    {
+        public abstract IComplexFormulaNode<TType, TResult> GetFormula();
+
+        #region Internals
+
+        IComplexFormulaNode IComplexFormulaGenerator.GetFormula() => GetFormula();
+
+        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);
+        }
+
+        public IComplexFormulaNode<TType, TResult> Property(Expression<Func<TType, TResult>> epxression)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Property(epxression);
+        }
+
+        public IComplexFormulaNode<TType, TResult> Constant(TResult constant)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Constant(constant);
+        }
+
+        public ComplexFormulaPartialAggregateNode<TType, TAggregate, TResult> Aggregate<TAggregate>(
+            AggregateCalculation calculation,
+            Func<IComplexFormulaGenerator<TAggregate, TResult>, IComplexFormulaNode<TAggregate, TResult>> expression,
+            Filter<TAggregate>? filter = null)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).Aggregate(calculation, expression, filter);
+        }
+
+        public ComplexFormulaPartial0ConditionNode<TType, TCondition, TResult> If<TCondition>(Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> left, Condition condition, Func<IComplexFormulaGenerator<TType, TCondition>, IComplexFormulaNode<TType, TCondition>> right)
+        {
+            return ((IComplexFormulaGenerator<TType, TResult>)InternalGenerator).If(left, condition, right);
+        }
+
+        #endregion
+    }
+
+    public class ComplexFormulaAttribute : Attribute
+    {
+        public IComplexFormulaGenerator Generator { get; }
+
+        public ComplexFormulaAttribute(Type generator)
+        {
+            var obj = Activator.CreateInstance(generator);
+            if(obj is IComplexFormulaGenerator g)
+            {
+                Generator = g;
+            }
+            else
+            {
+                throw new Exception($"{nameof(ComplexFormulaAttribute)}: {generator} is not a {typeof(IComplexFormulaGenerator)}!");
+            }
+        }
+    }
+
+    #endregion
+
+    #endregion
+
     #region Aggregates
 
     public enum AggregateCalculation

+ 50 - 2
InABox.Core/Query/Column.cs

@@ -13,11 +13,53 @@ using Newtonsoft.Json.Linq;
 
 namespace InABox.Core
 {
-    public interface IColumn
+    public interface IBaseColumn
+    {
+        /// <summary>
+        /// Unique name of this column.
+        /// </summary>
+        /// <remarks>
+        /// Every column needs a name to distinguish it from other columns, for example in query result tables, or in SQL queries.
+        /// </remarks>
+        string Name { get; }
+    }
+
+    public interface IBaseColumns
+    {
+        IEnumerable<IBaseColumn> Columns();
+    }
+
+    public interface IComplexColumn : IBaseColumn
+    {
+        IComplexFormulaNode Formula { get; }
+    }
+
+    public class ComplexColumn<T, TResult> : IComplexColumn
+    {
+        public string Name { get; }
+
+        public IComplexFormulaNode<T, TResult> Formula { get; }
+
+        public ComplexColumn(string name, IComplexFormulaNode<T, TResult> formula)
+        {
+            Name = name;
+            Formula = formula;
+        }
+
+        #region IComplexColumn
+
+        IComplexFormulaNode IComplexColumn.Formula => Formula;
+
+        #endregion
+    }
+
+    public interface IColumn : IBaseColumn
     {
         string Property { get; }
 
         Type Type { get; }
+
+        string IBaseColumn.Name => Property;
     }
 
     public static class Column
@@ -104,7 +146,7 @@ namespace InABox.Core
         public override string ToString() => Property;
     }
 
-    public interface IColumns : ISerializeBinary
+    public interface IColumns : ISerializeBinary, IBaseColumns
     {
         int Count { get; }
 
@@ -383,6 +425,12 @@ namespace InABox.Core
 
         #endregion
 
+        #region IBaseColumns
+
+        IEnumerable<IBaseColumn> IBaseColumns.Columns() => columns;
+
+        #endregion
+
         #region Add
 
         private Columns<T> Add(string column)

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1603 - 1494
inabox.database.sqlite/SQLiteProvider.cs


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác