Browse Source

Fixed MultiQuery serialisation

Kenric Nugteren 1 week ago
parent
commit
bff2b190f7

+ 103 - 0
InABox.Core/Client/Request.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Runtime.InteropServices.ComTypes;
+using System.Text.Json;
 using System.Text.Json.Serialization;
 using InABox.Core;
 
@@ -552,6 +553,7 @@ namespace InABox.Clients
 
     public interface IMultiQueryTableQuery
     {
+        [JsonPropertyOrder(0)]
         string Type { get; }
 
         IFilter? Filter { get; set; }
@@ -652,6 +654,107 @@ namespace InABox.Clients
         }
     }
 
+    public class MultiQueryRequestConverter : CustomJsonConverter<MultiQueryRequest>
+    {
+        private IMultiQueryTableQuery ReadQuery(ref Utf8JsonReader reader, JsonSerializerOptions options)
+        {
+            Type? type = null;
+            IFilter? filter = null;
+            IColumns? columns = null;
+            ISortOrder? sort = null;
+
+            ReadObject(ref reader, (ref Utf8JsonReader reader, string property) =>
+            {
+                if(property == "Type")
+                {
+                    var typeName = reader.GetString() ?? "";
+                    type = CoreUtils.GetEntity(typeName);
+                    if(type is null)
+                    {
+                        throw new JsonException($"Invalid type name {typeName}");
+                    }
+                }
+                else if(type is null)
+                {
+                    throw new JsonException($"'Type' expected as first field, got {property}");
+                }
+                else if(property == "Filter")
+                {
+                    filter = JsonSerializer.Deserialize(ref reader, typeof(Filter<>).MakeGenericType(type), options) as IFilter;
+                }
+                else if(property == "Columns")
+                {
+                    columns = JsonSerializer.Deserialize(ref reader, typeof(Columns<>).MakeGenericType(type), options) as IColumns;
+                }
+                else if(property == "Sort")
+                {
+                    sort = JsonSerializer.Deserialize(ref reader, typeof(SortOrder<>).MakeGenericType(type), options) as ISortOrder;
+                }
+                else
+                {
+                    reader.Skip();
+                }
+            });
+
+            if(type is null)
+            {
+                throw new JsonException($"'Type' field expected");
+            }
+            var query = (Activator.CreateInstance(typeof(MultiQueryTableQuery<>).MakeGenericType(type)) as IMultiQueryTableQuery)!;
+            query.Filter = filter;
+            query.Columns = columns;
+            query.Sort = sort;
+            return query;
+        }
+
+        public override MultiQueryRequest? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        {
+            if (reader.TokenType != JsonTokenType.StartObject)
+            {
+                throw new JsonException();
+            }
+
+            var multiQuery = new MultiQueryRequest();
+            ReadObject(ref reader, (ref Utf8JsonReader reader, string property) =>
+            {
+                if (property == "Queries")
+                {
+                    ReadObject(ref reader, (ref Utf8JsonReader reader, string key) =>
+                    {
+                        multiQuery.Queries[key] = ReadQuery(ref reader, options);
+                    });
+                }
+                else if (property == "Credentials")
+                {
+                    multiQuery.Credentials = JsonSerializer.Deserialize<Credentials>(ref reader, options) ?? new Credentials();
+                }
+                else
+                {
+                    reader.Skip();
+                }
+            });
+            return multiQuery;
+        }
+
+        public override void Write(Utf8JsonWriter writer, MultiQueryRequest value, JsonSerializerOptions options)
+        {
+            writer.WriteStartObject();
+
+            writer.WritePropertyName("Credentials");
+            JsonSerializer.Serialize(writer, value.Credentials, options);
+
+            writer.WriteStartObject("Queries");
+            foreach(var (key, query) in value.Queries)
+            {
+                writer.WritePropertyName(key);
+                JsonSerializer.Serialize(writer, query, options);
+            }
+            writer.WriteEndObject();
+
+            writer.WriteEndObject();
+        }
+    }
+
     public class MultiQueryResponse : Response, ISerializeBinary
     {
         public MultiQueryResponse()

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

@@ -767,14 +767,7 @@ namespace InABox.Core
     {
         public override bool CanConvert(Type objectType)
         {
-            if (objectType.IsConstructedGenericType)
-            {
-                var ot = objectType.GetGenericTypeDefinition();
-                var tt = typeof(Columns<>);
-                if (ot == tt)
-                    return true;
-            }
-            return false;
+            return typeof(IColumns).IsAssignableFrom(objectType);
         }
 
         public override IColumns? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
@@ -811,14 +804,7 @@ namespace InABox.Core
     {
         public override bool CanConvert(Type objectType)
         {
-            if (objectType.IsConstructedGenericType)
-            {
-                var ot = objectType.GetGenericTypeDefinition();
-                var tt = typeof(Column<>);
-                if (ot == tt)
-                    return true;
-            }
-            return false;
+            return typeof(IColumn).IsAssignableFrom(objectType);
         }
 
         public override IColumn? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

+ 1 - 9
InABox.Core/Query/Filter.cs

@@ -2113,15 +2113,7 @@ namespace InABox.Core
         
         public override bool CanConvert(Type objectType)
         {
-            if (objectType.IsConstructedGenericType)
-            {
-                var ot = objectType.GetGenericTypeDefinition();
-                var tt = typeof(Filter<>);
-                if (ot == tt)
-                    return true;
-            }
-
-            return false;
+            return typeof(IFilter).IsAssignableFrom(objectType);
         }
 
         public override IFilter? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

+ 1 - 9
InABox.Core/Query/SortOrder.cs

@@ -266,15 +266,7 @@ namespace InABox.Core
     {
         public override bool CanConvert(Type objectType)
         {
-            if (objectType.IsConstructedGenericType)
-            {
-                var ot = objectType.GetGenericTypeDefinition();
-                var tt = typeof(SortOrder<>);
-                if (ot == tt)
-                    return true;
-            }
-
-            return false;
+            return typeof(ISortOrder).IsAssignableFrom(objectType);
         }
 
         public override ISortOrder? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

+ 22 - 0
InABox.Core/Serialization.cs

@@ -54,6 +54,7 @@ namespace InABox.Core
             new ColumnJsonConverter(),
             new ColumnsJsonConverter(),
             new SortOrderJsonConverter(),
+            new MultiQueryRequestConverter(),
             new UserPropertiesJsonConverter(),
             new TypeJsonConverter(),
         };
@@ -972,6 +973,27 @@ namespace InABox.Core
                 return Enum.Parse<T>(reader.GetString());
             }
         }
+
+        protected delegate void ObjectPropertyHandler(ref Utf8JsonReader reader, string propertyName);
+
+        protected void ReadObject(ref Utf8JsonReader reader, ObjectPropertyHandler onProperty)
+        {
+            if (reader.TokenType != JsonTokenType.StartObject)
+            {
+                throw new JsonException();
+            }
+            while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
+            {
+                if(reader.TokenType != JsonTokenType.PropertyName)
+                {
+                    throw new JsonException();
+                }
+                var property = reader.GetString() ?? "";
+                reader.Read();
+                onProperty(ref reader, property);
+            }
+        }
+
         
         /// <summary>
         /// Write a value as a JSON object; note that some data types, like