123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Runtime.Serialization;
- using System.Text.Json;
- namespace InABox.Core
- {
- public enum SortDirection
- {
- Ascending,
- Descending
- }
- public interface ISortOrder : ISerializeBinary
- {
- SortDirection Direction { get; set; }
- Expression Expression { get; set; }
- IEnumerable<ISortOrder> Thens { get; }
- ISortOrder ThenBy(ISortOrder sortOrder);
- IEnumerable<String> ColumnNames();
- string AsOData();
- void SerializeBinary(CoreBinaryWriter writer);
- void DeserializeBinary(CoreBinaryReader reader);
- }
- public static class SortOrder
- {
- public static ISortOrder Create<T>(Type concrete, Expression<Func<T,object>> expression, SortDirection direction = SortDirection.Ascending)
- {
- if (!typeof(T).IsAssignableFrom(concrete))
- throw new Exception($"Columns: {concrete.EntityName()} does not implement {typeof(T).EntityName()}");
- var type = typeof(SortOrder<>).MakeGenericType(concrete);
- var property = CoreUtils.GetFullPropertyName(expression,".");
- var result = Activator.CreateInstance(type, property, direction );
- return (result as ISortOrder)!;
- }
- }
-
- public class SortOrder<T> : SerializableExpression<T>, ISortOrder // where T : Entity
- {
- public SortDirection Direction { get; set; }
- public List<SortOrder<T>> Thens { get; private set; }
- IEnumerable<ISortOrder> ISortOrder.Thens => Thens;
- //public SortOrder<T> Ascending()
- //{
- // Direction = SortOrder.Ascending;
- // return this;
- //}
- //public SortOrder<T> Descending()
- //{
- // Direction = SortOrder.Descending;
- // return this;
- //}
- ISortOrder ISortOrder.ThenBy(ISortOrder sortOrder)
- {
- if(sortOrder is SortOrder<T> order)
- {
- Thens.Add(order);
- }
- return this;
- }
- public SortOrder<T> ThenBy(Expression<Func<T, object?>> expression, SortDirection direction = SortDirection.Ascending)
- {
- var thenby = new SortOrder<T>(expression, direction);
- Thens.Add(thenby);
- return this;
- }
- #region Constructors
- public SortOrder()
- {
- Thens = new List<SortOrder<T>>();
- Direction = SortDirection.Ascending;
- }
- public SortOrder(Expression<Func<T, object?>> expression, SortDirection direction = SortDirection.Ascending)
- : base(expression)
- {
- Thens = new List<SortOrder<T>>();
- Direction = direction;
- }
- public SortOrder(string property, SortDirection direction = SortDirection.Ascending)
- {
- Thens = new List<SortOrder<T>>();
- Direction = direction;
- var iprop = DatabaseSchema.Property(typeof(T), property);
- Expression = iprop.Expression();
- }
- public SortOrder(SerializationInfo info, StreamingContext context)
- {
- Deserialize(info, context);
- }
- public static explicit operator SortOrder<T>(SortOrder<Entity> v)
- {
- if (v == null)
- return null;
- var json = Serialization.Serialize(v);
- json = json.Replace(typeof(Entity).EntityName(), typeof(T).EntityName());
- var result = Serialization.Deserialize<SortOrder<T>>(json);
- return result;
- }
- #endregion
- #region Display Functions
- public string AsOData()
- {
- var orderby = new Dictionary<SortDirection, string>
- {
- { SortDirection.Ascending, "asc" },
- { SortDirection.Descending, "desc" }
- };
- var prop = "";
- if (CoreUtils.TryFindMemberExpression(Expression, out var mexp))
- prop = CoreUtils.GetFullPropertyName(mexp, "/");
- else
- prop = Expression.ToString();
- var result = string.Format("{0} {1}", prop, orderby[Direction]);
- if (Thens != null && Thens.Count > 0)
- foreach (var then in Thens)
- {
- var ThenResult = then.AsOData();
- if (!string.IsNullOrEmpty(ThenResult))
- result = string.Format("{0}, {1}", result, ThenResult);
- }
- return result;
- }
- public override string ToString()
- {
- return AsOData();
- }
- public IEnumerable<string> ColumnNames()
- {
- yield return CoreUtils.ExpressionToString(typeof(T), Expression);
- foreach (var then in Thens)
- foreach (var x in then.ColumnNames())
- yield return x;
- }
- #endregion
- //public Expression<Func<T,Object>> AsExpression()
- //{
- // var param = Expression.Parameter(typeof(T), "x");
- // var result = Expression.Lambda<Func<T,Object>>(Expression,param);
- // return result;
- //}
- #region Serialization
- public override void Serialize(SerializationInfo info, StreamingContext context)
- {
- info.AddValue("Direction", Direction.ToString());
- if (Thens.Count > 0)
- info.AddValue("Thens", Thens, typeof(List<SortOrder<T>>));
- }
- public override void Deserialize(SerializationInfo info, StreamingContext context)
- {
- Direction = (SortDirection)Enum.Parse(typeof(SortDirection), (string)info.GetValue("Direction", typeof(string)));
- try
- {
- Thens = (List<SortOrder<T>>)info.GetValue("Thens", typeof(List<SortOrder<T>>));
- }
- catch
- {
- Thens = new List<SortOrder<T>>();
- }
- }
- #endregion
- #region Binary Serialization
- public void SerializeBinary(CoreBinaryWriter writer)
- {
- writer.SerialiseExpression(typeof(T), Expression, false);
- writer.Write((byte)Direction);
- writer.Write(Thens.Count);
- foreach (var then in Thens)
- {
- then.SerializeBinary(writer);
- }
- }
- public void DeserializeBinary(CoreBinaryReader reader)
- {
- Expression = reader.DeserialiseExpression(typeof(T));
- Direction = (SortDirection)reader.ReadByte();
- Thens.Clear();
- var nThens = reader.ReadInt32();
- for(int i = 0; i < nThens; ++i)
- {
- var then = new SortOrder<T>();
- then.DeserializeBinary(reader);
- Thens.Add(then);
- }
- }
- #endregion
- }
- public static class SortOrderSerialization
- {
- /// <summary>
- /// Inverse of <see cref="Write{T}(CoreBinaryWriter, SortOrder{T}?)"/>.
- /// </summary>
- /// <param name="reader"></param>
- /// <returns></returns>
- public static SortOrder<T>? ReadSortOrder<T>(this CoreBinaryReader reader)
- {
- if (reader.ReadBoolean())
- {
- var sortOrder = new SortOrder<T>();
- sortOrder.DeserializeBinary(reader);
- return sortOrder;
- }
- return null;
- }
- /// <summary>
- /// Inverse of <see cref="ReadSortOrder{T}(CoreBinaryReader)"/>.
- /// </summary>
- /// <param name="filter"></param>
- /// <param name="writer"></param>
- public static void Write<T>(this CoreBinaryWriter writer, SortOrder<T>? sortOrder)
- {
- if (sortOrder is null)
- {
- writer.Write(false);
- }
- else
- {
- writer.Write(true);
- sortOrder.SerializeBinary(writer);
- }
- }
- }
- public class SortOrderJsonConverter : CustomJsonConverter<ISortOrder>
- {
- public override bool CanConvert(Type objectType)
- {
- if (objectType.IsConstructedGenericType)
- {
- var ot = objectType.GetGenericTypeDefinition();
- var tt = typeof(SortOrder<>);
- if (ot == tt)
- return true;
- }
- return false;
- }
- public override ISortOrder? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType == JsonTokenType.Null)
- return null;
- var type = typeToConvert;
- var sExpr = "";
- SortDirection dir = default;
- List<ISortOrder> thens = new List<ISortOrder>();
- while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
- {
- var tag = reader.GetString();
- reader.Read();
- if (string.Equals(tag, "$type"))
- {
- var sType = reader.GetString();
- if (!string.IsNullOrWhiteSpace(sType))
- {
- type = Type.GetType(sType) ?? typeToConvert;
- }
- }
- else if (string.Equals(tag, "Expression"))
- sExpr = reader.GetString();
- else if (string.Equals(tag, "Direction"))
- dir = Enum.Parse<SortDirection>(reader.GetString());
- else if (string.Equals(tag, "Thens"))
- {
- while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
- {
- var then = Read(ref reader, typeof(ISortOrder), options);
- if (then != null)
- thens.Add(then);
- }
- }
- }
- var prop = (CoreUtils.StringToExpression(sExpr) as MemberExpression)!;
- var result = (Activator.CreateInstance(type, CoreUtils.GetFullPropertyName(prop, "."), dir) as ISortOrder)!;
- foreach(var then in thens)
- {
- result.ThenBy(then);
- }
- return result;
- }
- public override void Write(Utf8JsonWriter writer, ISortOrder value, JsonSerializerOptions options)
- {
- var type = value.GetType().GenericTypeArguments[0];
- var property = value.Expression;
- var prop = CoreUtils.ExpressionToString(type, property, true);
- var dir = value.Direction;
- writer.WriteStartObject();
-
- writer.WriteString("$type", value.GetType().FullName);
- writer.WriteString("Expression", prop);
- writer.WriteString("Direction", dir.ToString());
- if(value.Thens.Any())
- {
- writer.WritePropertyName("Thens");
- writer.WriteStartArray();
- foreach(var then in value.Thens)
- {
- Write(writer, then, options);
- }
- writer.WriteEndArray();
- }
- writer.WriteEndObject();
- }
- }
- }
|