Browse Source

Added a boolean NOT Filter operator

Kenric Nugteren 1 year ago
parent
commit
7ed8e8f7a2

+ 43 - 1
InABox.Core/Filter.cs

@@ -79,7 +79,8 @@ namespace InABox.Core
         InQuery,
         InQuery,
         All,
         All,
         None,
         None,
-        NotInQuery
+        NotInQuery,
+        Not = byte.MaxValue
     }
     }
 
 
 
 
@@ -218,6 +219,8 @@ namespace InABox.Core
         Operator Operator { get; set; }
         Operator Operator { get; set; }
         object? Value { get; set; }
         object? Value { get; set; }
 
 
+        bool IsNot { get; set; }
+
         IEnumerable<IFilter> Ands { get; }
         IEnumerable<IFilter> Ands { get; }
         IEnumerable<IFilter> Ors { get; }
         IEnumerable<IFilter> Ors { get; }
 
 
@@ -318,6 +321,8 @@ namespace InABox.Core
         IFilter All();
         IFilter All();
         IFilter None();
         IFilter None();
 
 
+        IFilter Not();
+
         string AsOData();
         string AsOData();
 
 
         IEnumerable<string> ColumnNames();
         IEnumerable<string> ColumnNames();
@@ -380,6 +385,8 @@ namespace InABox.Core
         
         
         public object? Value { get; set; }
         public object? Value { get; set; }
 
 
+        public bool IsNot { get; set; }
+
         IEnumerable<IFilter> IFilter.Ands => Ands;
         IEnumerable<IFilter> IFilter.Ands => Ands;
 
 
         IEnumerable<IFilter> IFilter.Ors => Ors;
         IEnumerable<IFilter> IFilter.Ors => Ors;
@@ -946,6 +953,16 @@ namespace InABox.Core
 
 
         #endregion
         #endregion
 
 
+        #region Not
+
+        public Filter<T> Not()
+        {
+            IsNot = !IsNot;
+            return this;
+        }
+        IFilter IFilter.Not() => Not();
+
+        #endregion
 
 
         #region All/None
         #region All/None
 
 
@@ -1138,6 +1155,7 @@ namespace InABox.Core
         {
         {
             info.AddValue("Operator", Operator.ToString());
             info.AddValue("Operator", Operator.ToString());
             info.AddValue("Value", Value);
             info.AddValue("Value", Value);
+            info.AddValue("IsNot", IsNot);
             if (Ands.Count > 0)
             if (Ands.Count > 0)
                 info.AddValue("Ands", Ands, typeof(List<Filter<T>>));
                 info.AddValue("Ands", Ands, typeof(List<Filter<T>>));
             if (Ors.Count > 0)
             if (Ors.Count > 0)
@@ -1150,6 +1168,7 @@ namespace InABox.Core
 
 
             Operator = (Operator)Enum.Parse(typeof(Operator), (string)info.GetValue("Operator", typeof(string)));
             Operator = (Operator)Enum.Parse(typeof(Operator), (string)info.GetValue("Operator", typeof(string)));
             Value = info.GetValue("Value", typeof(object));
             Value = info.GetValue("Value", typeof(object));
+            IsNot = info.GetBoolean("IsNot");
 
 
             try
             try
             {
             {
@@ -1548,6 +1567,10 @@ namespace InABox.Core
         public void SerializeBinary(CoreBinaryWriter writer)
         public void SerializeBinary(CoreBinaryWriter writer)
         {
         {
             writer.SerialiseExpression(typeof(T), Expression, false);
             writer.SerialiseExpression(typeof(T), Expression, false);
+            if (IsNot)
+            {
+                writer.Write((byte)Operator.Not);
+            }
             writer.Write((byte)Operator);
             writer.Write((byte)Operator);
 
 
             SerializeValue(writer, Value, true);
             SerializeValue(writer, Value, true);
@@ -1568,7 +1591,14 @@ namespace InABox.Core
         public void DeserializeBinary(CoreBinaryReader reader)
         public void DeserializeBinary(CoreBinaryReader reader)
         {
         {
             Expression = reader.DeserialiseExpression(typeof(T));
             Expression = reader.DeserialiseExpression(typeof(T));
+
             Operator = (Operator)reader.ReadByte();
             Operator = (Operator)reader.ReadByte();
+            if(Operator == Operator.Not)
+            {
+                IsNot = true;
+                Operator = (Operator)reader.ReadByte();
+            }
+
             var val = DeserializeValue(reader);
             var val = DeserializeValue(reader);
             var type = (Operator == Operator.InList || Operator == Operator.NotInList)
             var type = (Operator == Operator.InList || Operator == Operator.NotInList)
                 ? Expression.Type.MakeArrayType()
                 ? Expression.Type.MakeArrayType()
@@ -1659,6 +1689,10 @@ namespace InABox.Core
                     value
                     value
                 );
                 );
             }
             }
+            if (IsNot)
+            {
+                result = $"not {result}";
+            }
 
 
             if (Ands != null && Ands.Count > 0)
             if (Ands != null && Ands.Count > 0)
                 foreach (var and in Ands)
                 foreach (var and in Ands)
@@ -1933,6 +1967,9 @@ namespace InABox.Core
             writer.WritePropertyName("Operator");
             writer.WritePropertyName("Operator");
             writer.WriteValue(op);
             writer.WriteValue(op);
 
 
+            writer.WritePropertyName("IsNot");
+            writer.WriteValue(filter.IsNot);
+
             if (val is FilterConstant)
             if (val is FilterConstant)
             {
             {
                 writer.WritePropertyName("FilterConstant");
                 writer.WritePropertyName("FilterConstant");
@@ -2051,6 +2088,11 @@ namespace InABox.Core
             var exp = CoreUtils.StringToExpression(prop);
             var exp = CoreUtils.StringToExpression(prop);
             var op = (Operator)int.Parse(data["Operator"].ToString());
             var op = (Operator)int.Parse(data["Operator"].ToString());
 
 
+            if(data.TryGetValue("IsNot", out var isNotValue) && isNotValue is bool b)
+            {
+                result.IsNot = b;
+            }
+
             result.Expression = exp;
             result.Expression = exp;
             result.Operator = op;
             result.Operator = op;
             if(data.TryGetValue("Value", out var val))
             if(data.TryGetValue("Value", out var val))

+ 7 - 2
inabox.database.sqlite/SQLiteProvider.cs

@@ -1399,11 +1399,11 @@ namespace InABox.Database.SQLite
             var result = "";
             var result = "";
             if (filter.Operator == Operator.All)
             if (filter.Operator == Operator.All)
             {
             {
-                result = "1 = 1";
+                result = filter.IsNot ? "1 = 0" : "1 = 1";
             }
             }
             else if (filter.Operator == Operator.None)
             else if (filter.Operator == Operator.None)
             {
             {
-                result = "1 = 0";
+                result = filter.IsNot ? "1 = 1" : "1 = 0";
             }
             }
             else
             else
             {
             {
@@ -1506,6 +1506,11 @@ namespace InABox.Database.SQLite
 
 
                     }
                     }
                 }
                 }
+
+                if (filter.IsNot)
+                {
+                    result = $"(NOT {result})";
+                }
             }
             }
 
 
             var bChanged = false;
             var bChanged = false;

+ 17 - 6
inabox.wpf/DynamicGrid/Editors/FilterEditor/FilterNode.cs

@@ -74,7 +74,7 @@ public class FilterNode<T> : BaseFilterNode
         this.filterType = filterType;
         this.filterType = filterType;
 
 
         Property = new(filter.Expression) { Margin = new Thickness(0, 0, 5, 0) };
         Property = new(filter.Expression) { Margin = new Thickness(0, 0, 5, 0) };
-        Operator = new(filter.Operator) { Margin = new Thickness(0, 0, 5, 0) };
+        Operator = new(filter.Operator, filter.IsNot) { Margin = new Thickness(0, 0, 5, 0) };
 
 
         ValuePlaceHolder = CreateValuePlaceHolder();
         ValuePlaceHolder = CreateValuePlaceHolder();
         
         
@@ -141,17 +141,28 @@ public class FilterNode<T> : BaseFilterNode
 
 
     public override Filter<T>? GetFilter()
     public override Filter<T>? GetFilter()
     {
     {
-        if (Operator.SelectedOperator == Core.Operator.All)
-            return new Filter<T>().All();
+        var op = Operator.SelectedOperator;
+        var isNot = Operator.IsNot;
+        if (op == Core.Operator.All)
+        {
+            return isNot
+                ? new Filter<T>().None()
+                : new Filter<T>().All();
+        }
         if (Operator.SelectedOperator == Core.Operator.None)
         if (Operator.SelectedOperator == Core.Operator.None)
-            return new Filter<T>().None();
+        {
+            return isNot
+                ? new Filter<T>().All()
+                : new Filter<T>().None();
+        }
 
 
         if (Property.SelectedProperty is null)
         if (Property.SelectedProperty is null)
             return null;
             return null;
         
         
         var filter = new Filter<T>();
         var filter = new Filter<T>();
         filter.Expression = CoreUtils.CreateMemberExpression(typeof(T), Property.SelectedProperty);
         filter.Expression = CoreUtils.CreateMemberExpression(typeof(T), Property.SelectedProperty);
-        filter.Operator = Operator.SelectedOperator;
+        filter.Operator = op;
+        filter.IsNot = isNot;
         filter.Value = Constant?.SelectedConstant ?? CustomValue?.Value ?? Value.Value;
         filter.Value = Constant?.SelectedConstant ?? CustomValue?.Value ?? Value.Value;
 
 
         foreach(var and in Ands.GetFilters())
         foreach(var and in Ands.GetFilters())
@@ -338,7 +349,7 @@ public class FilterNode<T> : BaseFilterNode
         }
         }
     }
     }
 
 
-    private void Operator_OperatorChanged(Operator op)
+    private void Operator_OperatorChanged(Operator op, bool isNot)
     {
     {
 
 
         if (Constant is not null)
         if (Constant is not null)

+ 74 - 13
inabox.wpf/DynamicGrid/Editors/FilterEditor/Nodes/OperatorNode.cs

@@ -1,39 +1,100 @@
 using System;
 using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Controls;
 using InABox.Core;
 using InABox.Core;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Xceed.Wpf.Toolkit.Primitives;
 
 
 namespace InABox.DynamicGrid;
 namespace InABox.DynamicGrid;
 
 
-public class OperatorNode : ComboBox
+public class OperatorNode : StackPanel
 {
 {
-    public delegate void OperatorChangedHandler(Operator op);
+    public delegate void OperatorChangedHandler(Operator op, bool isNot);
 
 
     public event OperatorChangedHandler? OperatorChanged;
     public event OperatorChangedHandler? OperatorChanged;
 
 
-    public Operator SelectedOperator => (Operator)SelectedItem;
+    public Operator SelectedOperator => (Operator)_boxes.Last().SelectedItem;
 
 
-    public OperatorNode(Operator op)
-    {
-        SetResourceReference(StyleProperty, typeof(ComboBox));
+    public bool IsNot => _boxes.Count % 2 == 0;
+
+    private List<ComboBox> _boxes = new List<ComboBox>();
 
 
+    public OperatorNode(Operator op, bool isNot)
+    {
+        Orientation = Orientation.Horizontal;
         VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
         VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
-        VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
+
+        if (isNot)
+        {
+            AddBox(Operator.Not);
+            AddBox(op);
+        }
+        else
+        {
+            AddBox(op);
+        }
+    }
+
+    private ComboBox AddBox(Operator selectedItem)
+    {
+        var box = new ComboBox();
+
+        box.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
+        box.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
 
 
         foreach (var value in Enum.GetValues<Operator>())
         foreach (var value in Enum.GetValues<Operator>())
         {
         {
-            Items.Add(value);
+            box.Items.Add(value);
         }
         }
-        SelectedItem = op;
-        SelectionChanged += ComboBox_SelectionChanged;
+        box.SelectedItem = selectedItem;
+        box.SelectionChanged += ComboBox_SelectionChanged;
+
+        if(_boxes.Count > 0)
+        {
+            box.Margin = new Thickness(5, 0, 0, 0);
+        }
+
+        _boxes.Add(box);
+        Children.Add(box);
+
+        return box;
     }
     }
+
     public void Clear()
     public void Clear()
     {
     {
-        SelectedIndex = 0;
+        _boxes.Clear();
+        Children.Clear();
+
+        AddBox(default);
+        OperatorChanged?.Invoke(default, false);
     }
     }
 
 
     private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
     private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
     {
     {
-        var selected = (Operator?)SelectedItem ?? Operator.IsEqualTo;
-        OperatorChanged?.Invoke(selected);
+        if (sender is not ComboBox box) return;
+
+        var selected = (Operator?)box.SelectedItem ?? Operator.IsEqualTo;
+
+        if (box == _boxes.Last())
+        {
+            if(selected == Operator.Not)
+            {
+                AddBox(default);
+                OperatorChanged?.Invoke(SelectedOperator, IsNot);
+            }
+        }
+        else
+        {
+            if(selected != Operator.Not)
+            {
+                var idx = _boxes.IndexOf(box);
+                Children.RemoveRange(idx + 1, _boxes.Count - idx);
+                _boxes.RemoveRange(idx + 1, _boxes.Count - (idx + 1));
+                OperatorChanged?.Invoke(SelectedOperator, IsNot);
+            }
+        }
+        OperatorChanged?.Invoke(SelectedOperator, IsNot);
     }
     }
 }
 }