|
@@ -220,7 +220,9 @@ namespace InABox.Core
|
|
|
|
|
|
public interface IFilter : ISerializeBinary
|
|
|
{
|
|
|
- Expression Expression { get; set; }
|
|
|
+ string Property { get; set; }
|
|
|
+ Type Type { get; }
|
|
|
+
|
|
|
Operator Operator { get; set; }
|
|
|
object? Value { get; set; }
|
|
|
|
|
@@ -381,8 +383,45 @@ namespace InABox.Core
|
|
|
|
|
|
}
|
|
|
|
|
|
- public class Filter<T> : SerializableExpression<T>, IFilter
|
|
|
+ public class Filter<T> : IFilter
|
|
|
{
|
|
|
+ public Type Type => PropertyDefinition?.PropertyType ?? typeof(object);
|
|
|
+
|
|
|
+ private string _property;
|
|
|
+ public string Property
|
|
|
+ {
|
|
|
+ get => _property;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _property = value;
|
|
|
+ _propertyDefinition = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private IProperty? _propertyDefinition;
|
|
|
+ public IProperty? PropertyDefinition
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ if (Property.IsNullOrWhiteSpace())
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _propertyDefinition ??= DatabaseSchema.PropertyStrict(typeof(T), Property);
|
|
|
+ return _propertyDefinition;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _propertyDefinition = value;
|
|
|
+ if(value != null)
|
|
|
+ {
|
|
|
+ Property = value.Name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
public Filter<T>? Parent { get; set; }
|
|
|
|
|
@@ -585,73 +624,42 @@ namespace InABox.Core
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
- //public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
|
- //{
|
|
|
- // base.GetObjectData(info, context);
|
|
|
-
|
|
|
- // if (info != null)
|
|
|
- // info.AddValue("ErrorMessage", this.ErrorMessage);
|
|
|
- //}
|
|
|
-
|
|
|
-
|
|
|
- public Filter<T1> Attach<T1>(Expression<Func<T1, object>> anchor)
|
|
|
- {
|
|
|
- var result = new Filter<T1>();
|
|
|
- result.Expression = CoreUtils.ConvertExpression(typeof(T), Expression, typeof(T1), anchor);
|
|
|
- result.Operator = Operator;
|
|
|
- result.Value = Value;
|
|
|
- foreach (var and in Ands)
|
|
|
- and.Attach(anchor);
|
|
|
- foreach (var or in Ors)
|
|
|
- or.Attach(anchor);
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
#region Constructors
|
|
|
|
|
|
public Filter()
|
|
|
{
|
|
|
Ands = new List<Filter<T>>();
|
|
|
Ors = new List<Filter<T>>();
|
|
|
+
|
|
|
+ _property = "";
|
|
|
}
|
|
|
|
|
|
- public Filter(Column<T> column): base(column.Expression)
|
|
|
+ public Filter(Column<T> column) : this()
|
|
|
{
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
+ _property = column.Property;
|
|
|
+ _propertyDefinition = column.PropertyDefinition;
|
|
|
}
|
|
|
-
|
|
|
- //public Filter(object expression) : base()
|
|
|
- //{
|
|
|
- // Ands = new List<Filter<T>>();
|
|
|
- // Ors = new List<Filter<T>>();
|
|
|
- //}
|
|
|
|
|
|
- public Filter(Expression<Func<T, object?>> expression) : base(expression)
|
|
|
+ public Filter(Expression<Func<T, object?>> expression) : this()
|
|
|
{
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
+ _property = CoreUtils.GetFullPropertyName(expression, ".");
|
|
|
}
|
|
|
|
|
|
- public Filter(string property) : base(property)
|
|
|
+ public Filter(IProperty property) : this()
|
|
|
{
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
+ _property = property.Name;
|
|
|
+ _propertyDefinition = property;
|
|
|
}
|
|
|
|
|
|
- public Filter(string property, Operator op, object value) : base(property)
|
|
|
+ public Filter(string property) : this()
|
|
|
{
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
- Operator = op;
|
|
|
- Value = value;
|
|
|
+ _property = property;
|
|
|
}
|
|
|
|
|
|
- public Filter(SerializationInfo info, StreamingContext context)
|
|
|
+ public Filter(string property, Operator op, object value) : this(property)
|
|
|
{
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
- Deserialize(info, context);
|
|
|
+ Operator = op;
|
|
|
+ Value = value;
|
|
|
}
|
|
|
|
|
|
public static explicit operator Filter<T>?(Filter<Entity>? v)
|
|
@@ -677,13 +685,10 @@ namespace InABox.Core
|
|
|
public Filter<TNew> Cast<TNew>()
|
|
|
where TNew : T
|
|
|
{
|
|
|
- var prop = "";
|
|
|
- if (CoreUtils.TryFindMemberExpression(Expression, out var mexp))
|
|
|
- {
|
|
|
- prop = CoreUtils.GetFullPropertyName(mexp, ".");
|
|
|
- }
|
|
|
+ var filter = new Filter<TNew>();
|
|
|
+ filter._property = _property;
|
|
|
+ filter._propertyDefinition = _propertyDefinition;
|
|
|
|
|
|
- var filter = new Filter<TNew>(prop);
|
|
|
filter.Operator = Operator;
|
|
|
filter.Value = Value;
|
|
|
filter.IsNot = IsNot;
|
|
@@ -1046,8 +1051,7 @@ namespace InABox.Core
|
|
|
{
|
|
|
CoreUtils.TryFindMemberExpression(expression.Body, out var me);
|
|
|
|
|
|
- var filter = new Filter<T>();
|
|
|
- filter.Expression = me;
|
|
|
+ var filter = new Filter<T>(CoreUtils.MemberExpressionToString(me));
|
|
|
filter.Operator = includes.Equals(ListOperator.Includes) ? Operator.IsEqualTo : Operator.IsNotEqualTo;
|
|
|
filter.Value = value;
|
|
|
|
|
@@ -1116,130 +1120,6 @@ namespace InABox.Core
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
- #region Expression Functions
|
|
|
-
|
|
|
- public Expression<Func<T, bool>> AsExpression()
|
|
|
- {
|
|
|
- var expression = Expression;
|
|
|
- if (expression is null)
|
|
|
- throw new Exception("Expression is null");
|
|
|
-
|
|
|
- var param = Expression.Parameter(typeof(T), "x");
|
|
|
- //Expression expr = param;
|
|
|
-
|
|
|
- Expression constant = Expression.Constant(null, typeof(object));
|
|
|
-
|
|
|
- //expr = Expression;
|
|
|
-
|
|
|
- if (Value != null)
|
|
|
- {
|
|
|
- var valType = Value.GetType();
|
|
|
-
|
|
|
- var propType = expression.Type;
|
|
|
-
|
|
|
- if (valType.Equals(typeof(string)) && propType.Equals(typeof(Guid)))
|
|
|
- constant = Expression.Constant(Guid.Parse(Value.ToString()), propType);
|
|
|
- else if (valType.Equals(typeof(string)) && propType.Equals(typeof(bool)))
|
|
|
- constant = Expression.Constant(bool.Parse(Value.ToString()), propType);
|
|
|
- else if (valType.Equals(typeof(string)) && propType.Equals(typeof(TimeSpan)))
|
|
|
- constant = Expression.Constant(TimeSpan.Parse(Value.ToString()), propType);
|
|
|
- else if (valType.Equals(typeof(string)) && propType.Equals(typeof(ScriptType)))
|
|
|
- constant = Expression.Constant((ScriptType)int.Parse(Value.ToString()), propType);
|
|
|
- //else if (valType.Equals(typeof(String)) && propType.Equals(typeof(DateTime)))
|
|
|
- // constant = Expression.Constant(JsonConvert.DeserializeObject<DateTime>(Value.ToString()), propType);
|
|
|
-
|
|
|
- else
|
|
|
- try
|
|
|
- {
|
|
|
- constant = Expression.Constant(Value, expression.Type);
|
|
|
- //constant = Expression.Constant(Value, propType);
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- var val = Value;
|
|
|
-
|
|
|
- if (!propType.Equals(valType) && !(val is FilterConstant))
|
|
|
- {
|
|
|
- val = CoreUtils.ChangeType(val, propType);
|
|
|
- }
|
|
|
- constant = Expression.Constant(val, propType);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Expression final = Operator switch
|
|
|
- {
|
|
|
- Operator.IsEqualTo => Expression.Equal(expression, constant),
|
|
|
- Operator.IsNotEqualTo => Expression.NotEqual(expression, constant),
|
|
|
- Operator.IsGreaterThan => Expression.GreaterThan(expression, constant),
|
|
|
- Operator.IsGreaterThanOrEqualTo => Expression.GreaterThanOrEqual(expression, constant),
|
|
|
- Operator.IsLessThan => Expression.LessThan(expression, constant),
|
|
|
- Operator.IsLessThanOrEqualTo => Expression.LessThanOrEqual(expression, constant),
|
|
|
- Operator.Contains => CreateContainsExpression(expression, constant),
|
|
|
- _ => throw new Exception("Invalid Operator"),
|
|
|
- };
|
|
|
- var result = Expression.Lambda<Func<T, bool>>(final, param);
|
|
|
- if (Ands != null)
|
|
|
- foreach (var filter in Ands)
|
|
|
- result = result.And(filter.AsExpression());
|
|
|
- if (Ors != null)
|
|
|
- foreach (var filter in Ors)
|
|
|
- result = result.Or(filter.AsExpression());
|
|
|
-
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- private Expression CreateContainsExpression(Expression expr, Expression constant)
|
|
|
- {
|
|
|
- var parameterExp = Expression.Parameter(typeof(string), "type");
|
|
|
- var method = typeof(string).GetTypeInfo().GetMethod("Contains", new[] { typeof(string) });
|
|
|
- var containsMethodExp = Expression.Call(expr, method, constant);
|
|
|
- return containsMethodExp;
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region Serialization
|
|
|
-
|
|
|
- public override void Serialize(SerializationInfo info, StreamingContext context)
|
|
|
- {
|
|
|
- info.AddValue("Operator", Operator.ToString());
|
|
|
- info.AddValue("Value", Value);
|
|
|
- info.AddValue("IsNot", IsNot);
|
|
|
- if (Ands.Count > 0)
|
|
|
- info.AddValue("Ands", Ands, typeof(List<Filter<T>>));
|
|
|
- if (Ors.Count > 0)
|
|
|
- info.AddValue("Ors", Ors, typeof(List<Filter<T>>));
|
|
|
- }
|
|
|
-
|
|
|
- public override void Deserialize(SerializationInfo info, StreamingContext context)
|
|
|
- {
|
|
|
- //Expression = CoreUtils.StringToExpression(typeof(T), (String)info.GetValue("Expression", typeof(String)));
|
|
|
-
|
|
|
- Operator = (Operator)Enum.Parse(typeof(Operator), (string)info.GetValue("Operator", typeof(string)));
|
|
|
- Value = info.GetValue("Value", typeof(object));
|
|
|
- IsNot = info.GetBoolean("IsNot");
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- Ands = (List<Filter<T>>)info.GetValue("Ands", typeof(List<Filter<T>>));
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- Ands = new List<Filter<T>>();
|
|
|
- }
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- Ors = (List<Filter<T>>)info.GetValue("Ors", typeof(List<Filter<T>>));
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- Ors = new List<Filter<T>>();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
#region Binary Serialisation
|
|
|
|
|
|
private enum ValueType
|
|
@@ -1615,7 +1495,10 @@ namespace InABox.Core
|
|
|
|
|
|
public void SerializeBinary(CoreBinaryWriter writer)
|
|
|
{
|
|
|
- writer.SerialiseExpression(typeof(T), Expression, false);
|
|
|
+ // For compatability purposes when redesigning system to no longer use Serializable Expression.
|
|
|
+ writer.Write((byte)0);
|
|
|
+
|
|
|
+ writer.Write(Property);
|
|
|
if (IsNot)
|
|
|
{
|
|
|
writer.Write((byte)Operator.Not);
|
|
@@ -1639,7 +1522,10 @@ namespace InABox.Core
|
|
|
|
|
|
public void DeserializeBinary(CoreBinaryReader reader)
|
|
|
{
|
|
|
- Expression = reader.DeserialiseExpression(typeof(T));
|
|
|
+ // For compatability purposes when redesigning system to no longer use Serializable Expression.
|
|
|
+ reader.ReadByte();
|
|
|
+
|
|
|
+ Property = reader.ReadString();
|
|
|
|
|
|
Operator = (Operator)reader.ReadByte();
|
|
|
if(Operator == Operator.Not)
|
|
@@ -1650,8 +1536,8 @@ namespace InABox.Core
|
|
|
|
|
|
var val = DeserializeValue(reader);
|
|
|
var type = (Operator == Operator.InList || Operator == Operator.NotInList)
|
|
|
- ? Expression.Type.MakeArrayType()
|
|
|
- : Expression.Type;
|
|
|
+ ? Type.MakeArrayType()
|
|
|
+ : Type;
|
|
|
Value = CoreUtils.ChangeType(val, type);
|
|
|
|
|
|
Ands.Clear();
|
|
@@ -1718,23 +1604,15 @@ namespace InABox.Core
|
|
|
{
|
|
|
result = "None";
|
|
|
}
|
|
|
- else if (Expression != null)
|
|
|
+ else if (Property != null)
|
|
|
{
|
|
|
var value = "null";
|
|
|
if (Value != null)
|
|
|
{
|
|
|
value = ValueToString(Value);
|
|
|
}
|
|
|
-
|
|
|
- string prop;
|
|
|
- if (CoreUtils.TryFindMemberExpression(Expression, out var mexp))
|
|
|
- prop = CoreUtils.GetFullPropertyName(mexp, "/");
|
|
|
- else
|
|
|
- prop = Expression.ToString();
|
|
|
-
|
|
|
-
|
|
|
result = string.Format("(" + operators[Operator] + ")",
|
|
|
- prop,
|
|
|
+ Property,
|
|
|
value
|
|
|
);
|
|
|
}
|
|
@@ -1774,7 +1652,7 @@ namespace InABox.Core
|
|
|
public IEnumerable<string> ColumnNames()
|
|
|
{
|
|
|
List<String> result = new List<string>();
|
|
|
- result.Add(CoreUtils.ExpressionToString(typeof(T), Expression));
|
|
|
+ result.Add(Property);
|
|
|
foreach (var and in Ands)
|
|
|
result.AddRange(and.ColumnNames());
|
|
|
foreach (var or in Ors)
|
|
@@ -2019,11 +1897,10 @@ namespace InABox.Core
|
|
|
writer.WriteNull();
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- var property = filter.Expression;
|
|
|
+
|
|
|
//MethodInfo mi = value.GetType().GetTypeInfo().GetMethod("ExpressionToString");
|
|
|
//String prop = mi.Invoke(value, new object[] { property, true }) as String;
|
|
|
- var prop = CoreUtils.ExpressionToString(value.GetType().GenericTypeArguments[0], property, true);
|
|
|
+ var prop = filter.Property;
|
|
|
|
|
|
var op = filter.Operator;
|
|
|
var val = filter.Value;
|
|
@@ -2060,7 +1937,7 @@ namespace InABox.Core
|
|
|
else
|
|
|
{
|
|
|
writer.WritePropertyName("Value");
|
|
|
- var valType = val == null ? property.Type : val.GetType();
|
|
|
+ var valType = val == null ? filter.Type : val.GetType();
|
|
|
if (valType.IsArray)
|
|
|
{
|
|
|
writer.WriteStartArray();
|
|
@@ -2162,7 +2039,6 @@ namespace InABox.Core
|
|
|
var result = (Activator.CreateInstance(finaltype) as IFilter)!;
|
|
|
|
|
|
var prop = data["Expression"].ToString();
|
|
|
- var exp = CoreUtils.StringToExpression(prop);
|
|
|
var op = (Operator)int.Parse(data["Operator"].ToString());
|
|
|
|
|
|
if(data.TryGetValue("IsNot", out var isNotValue) && isNotValue is bool b)
|
|
@@ -2170,7 +2046,7 @@ namespace InABox.Core
|
|
|
result.IsNot = b;
|
|
|
}
|
|
|
|
|
|
- result.Expression = exp;
|
|
|
+ result.Property = prop;
|
|
|
result.Operator = op;
|
|
|
if(data.TryGetValue("Value", out var val))
|
|
|
{
|
|
@@ -2180,7 +2056,7 @@ namespace InABox.Core
|
|
|
val = Activator.CreateInstance(typeof(SubQuery<>).MakeGenericType(CoreUtils.GetEntity(wrapper.Type)), null, null);
|
|
|
Serialization.DeserializeInto(wrapper.SerializedSubquery, val);
|
|
|
}
|
|
|
- result.Value = CoreUtils.ChangeType(val, exp.Type);
|
|
|
+ result.Value = CoreUtils.ChangeType(val, result.Type);
|
|
|
}
|
|
|
else if(data.TryGetValue("FilterConstant", out var filterConstant))
|
|
|
{
|