Bladeren bron

Merge remote-tracking branch 'origin/kenric' into frank

frogsoftware 9 maanden geleden
bovenliggende
commit
27ba30422f

+ 64 - 24
InABox.Core/BaseObject.cs

@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json;
+using System;
 using System.Collections;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -49,7 +50,11 @@ namespace InABox.Core
     }
     public class OriginalValues : IOriginalValues
     {
-        private readonly ConcurrentDictionary<string, object?> Dictionary = new ConcurrentDictionary<string, object?>();
+        public OriginalValues()
+        {
+        }
+
+        public ConcurrentDictionary<string, object?> Dictionary { get; set; } = new ConcurrentDictionary<string, object?>();
 
         public object? this[string key] { get => Dictionary[key]; set => Dictionary[key] = value; }
 
@@ -83,7 +88,7 @@ namespace InABox.Core
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
     }
 
-    public interface ILoadedColumns
+    public interface ILoadedColumns : IEnumerable<string>
     {
         public bool Add(string key);
 
@@ -102,6 +107,16 @@ namespace InABox.Core
         {
             return Columns.Contains(key);
         }
+
+        public IEnumerator<string> GetEnumerator()
+        {
+            return Columns.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return Columns.GetEnumerator();
+        }
     }
 
     /// <summary>
@@ -186,9 +201,10 @@ namespace InABox.Core
 
         private bool bChanged;
 
-        [DoNotPersist]
         private IOriginalValues _originalValues;
-        public IOriginalValues OriginalValues
+        [DoNotPersist]
+        [DoNotSerialize]
+        public IOriginalValues OriginalValueList
         {
             get
             {
@@ -197,8 +213,32 @@ namespace InABox.Core
             }
         }
 
+        [DoNotPersist]
+        public ConcurrentDictionary<string, object?>? OriginalValues
+        {
+            get
+            {
+                if(OriginalValueList is OriginalValues v)
+                {
+                    return v.Dictionary;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            set
+            {
+                if(value != null && OriginalValueList is OriginalValues v)
+                {
+                    v.Dictionary = value;
+                }
+            }
+        }
+
         [DoNotPersist]
         [DoNotSerialize]
+        [JsonIgnore]
         public ILoadedColumns LoadedColumns { get; set; }
 
         protected virtual void SetChanged(string name, object? before, object? after)
@@ -232,7 +272,7 @@ namespace InABox.Core
 
         private bool QueryChanged()
         {
-            if (OriginalValues.Any())
+            if (OriginalValueList.Any())
                 return true;
 
             foreach (var oo in DatabaseSchema.GetSubObjects(this))
@@ -261,8 +301,8 @@ namespace InABox.Core
             if (!BaseObjectExtensions.HasChanged(before, after))
                 return;
 
-            if (!OriginalValues.ContainsKey(name))
-                OriginalValues[name] = before;
+            if (!OriginalValueList.ContainsKey(name))
+                OriginalValueList[name] = before;
             SetChanged(name, before, after);
         }
 
@@ -286,7 +326,7 @@ namespace InABox.Core
             var bObs = IsObserving();
             SetObserving(false);
 
-            foreach (var (key, value) in OriginalValues)
+            foreach (var (key, value) in OriginalValueList)
             {
                 try
                 {
@@ -306,7 +346,7 @@ namespace InABox.Core
                 }
             }
 
-            OriginalValues.Clear();
+            OriginalValueList.Clear();
 
 
             bChanged = false;
@@ -322,7 +362,7 @@ namespace InABox.Core
         {
             bApplyingChanges = true;
 
-            OriginalValues.Clear();
+            OriginalValueList.Clear();
 
             bChanged = false;
 
@@ -338,7 +378,7 @@ namespace InABox.Core
             var type = GetType();
             try
             {
-                foreach (var (key, _) in OriginalValues)
+                foreach (var (key, _) in OriginalValueList)
                     try
                     {
                         if (UserProperties.ContainsKey(key))
@@ -451,7 +491,7 @@ namespace InABox.Core
                 prop.Setter()(Object, value);
                 if(BaseObjectExtensions.HasChanged(oldValue, value))
                 {
-                    Object.OriginalValues[prop.Name] = oldValue;
+                    Object.OriginalValueList[prop.Name] = oldValue;
                 }
             }
             Object.SetObserving(bObs);
@@ -490,13 +530,13 @@ namespace InABox.Core
 
         public static bool HasOriginalValue<T>(this T sender, string propertyname) where T : BaseObject
         {
-            return sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propertyname);
+            return sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propertyname);
         }
 
         public static TType GetOriginalValue<T, TType>(this T sender, string propertyname) where T : BaseObject
         {
-            return sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propertyname)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[propertyname], typeof(TType))
+            return sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propertyname)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[propertyname], typeof(TType))
                 : default;
         }
 
@@ -534,7 +574,7 @@ namespace InABox.Core
                 {
                     var isLocal = !property.HasParentEntityLink()
                         || (property.Parent?.HasParentEntityLink() != true && property.Name.EndsWith(".ID"));
-                    if (isLocal && sender.OriginalValues.TryGetValue(property.Name, out var value))
+                    if (isLocal && sender.OriginalValueList.TryGetValue(property.Name, out var value))
                     {
                         result[property.Name] = value;
                     }
@@ -596,36 +636,36 @@ namespace InABox.Core
         
         public static void SetOriginalValue<T, TType>(this T sender, string propertyname, TType value) where T : BaseObject
         {
-            sender.OriginalValues[propertyname] = value;
+            sender.OriginalValueList[propertyname] = value;
         }
 
         public static bool HasOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property) where T : BaseObject
         {
             //var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
             String propname = CoreUtils.GetFullPropertyName(property, ".");
-            return !String.IsNullOrWhiteSpace(propname) && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propname);
+            return !String.IsNullOrWhiteSpace(propname) && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propname);
         }
 
         public static TType GetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            return prop != null && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(prop.Name)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[prop.Name], typeof(TType))
+            return prop != null && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(prop.Name)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[prop.Name], typeof(TType))
                 : default;
         }
         
         public static TType GetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property, TType defaultValue) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            return prop != null && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(prop.Name)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[prop.Name], typeof(TType))
+            return prop != null && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(prop.Name)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[prop.Name], typeof(TType))
                 : defaultValue;
         }
 
         public static void SetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property, TType value) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            sender.OriginalValues[prop.Name] = value;
+            sender.OriginalValueList[prop.Name] = value;
         }
     }
 

+ 10 - 0
InABox.Core/CoreTable/CoreTable.cs

@@ -321,6 +321,16 @@ namespace InABox.Core
             }
             return list;
         }
+
+        public BaseObject[] ToArray(Type T)
+        {
+            var arr = new BaseObject[Rows.Count];
+            for(int i = 0; i < Rows.Count; ++i)
+            {
+                arr[i] = Rows[i].ToObject(T);
+            }
+            return arr;
+        }
         public T[] ToArray<T>() where T : BaseObject, new()
         {
             var arr = new T[Rows.Count];

+ 5 - 5
InABox.Core/EnclosedEntity.cs

@@ -11,9 +11,9 @@ namespace InABox.Core
     public abstract class EnclosedEntity : BaseObject, IEnclosedEntity
     {
 
-        private BaseObject _linkedParent;
+        private BaseObject? _linkedParent;
 
-        private string _linkedPath;
+        private string? _linkedPath;
 
         public void SetLinkedParent(BaseObject parent)
         {
@@ -35,13 +35,13 @@ namespace InABox.Core
             return new SubObjectLoadedColumns(this);
         }
 
-        public BaseObject GetLinkedParent() => _linkedParent;
+        public BaseObject? GetLinkedParent() => _linkedParent;
 
-        public string GetLinkedPath() => _linkedPath;
+        public string? GetLinkedPath() => _linkedPath;
         
         protected override void DoPropertyChanged(string name, object? before, object? after)
         {
-            LinkedProperties.GetParent(this).CascadePropertyChanged(LinkedProperties.GetPath(this) + "." + name, before, after);
+            LinkedProperties.GetParent(this)?.CascadePropertyChanged(LinkedProperties.GetPath(this) + "." + name, before, after);
 
             if (LinkedProperties.Find(this, name, out var link, out var parent))
             {

+ 5 - 5
InABox.Core/EntityLink.cs

@@ -28,9 +28,9 @@ namespace InABox.Core
         [DoNotSerialize]
         protected BaseObject? LinkedEntity() => _linkedentity?.Invoke();*/
 
-        private BaseObject _linkedParent;
+        private BaseObject? _linkedParent;
 
-        private string _linkedPath;
+        private string? _linkedPath;
 
         public void SetLinkedParent(BaseObject parent)
         {
@@ -42,9 +42,9 @@ namespace InABox.Core
             _linkedPath = path;
         }
 
-        public BaseObject GetLinkedParent() => _linkedParent;
+        public BaseObject? GetLinkedParent() => _linkedParent;
 
-        public string GetLinkedPath() => _linkedPath;
+        public string? GetLinkedPath() => _linkedPath;
 
         protected override IOriginalValues CreateOriginalValues()
         {
@@ -144,7 +144,7 @@ namespace InABox.Core
 
         protected override void DoPropertyChanged(string name, object? before, object? after)
         {
-            LinkedProperties.GetParent(this).CascadePropertyChanged(LinkedProperties.GetPath(this) + "." + name, before, after);
+            LinkedProperties.GetParent(this)?.CascadePropertyChanged(LinkedProperties.GetPath(this) + "." + name, before, after);
 
             if (LinkedProperties.Find(this, name, out var link, out var parent))
             {

+ 1 - 1
InABox.Core/Imports/BaseImporter.cs

@@ -75,7 +75,7 @@ namespace InABox.Core
             //var prop = CoreUtils.GetProperty(typeof(T), property);
             var type = p2.PropertyType;
 
-            item.OriginalValues[mapping.Property] = CoreUtils.GetPropertyValue(item, mapping.Property);
+            item.OriginalValueList[mapping.Property] = CoreUtils.GetPropertyValue(item, mapping.Property);
 
             if (type == typeof(string))
             {

+ 19 - 11
InABox.Core/LinkedProperties.cs

@@ -9,11 +9,11 @@ namespace InABox.Core
 {
     public interface ISubObject
     {
-        BaseObject GetLinkedParent();
+        BaseObject? GetLinkedParent();
 
         void SetLinkedParent(BaseObject obj);
 
-        string GetLinkedPath();
+        string? GetLinkedPath();
 
         void SetLinkedPath(string path);
     }
@@ -27,7 +27,7 @@ namespace InABox.Core
         {
             get
             {
-                _rootDictionary ??= LinkedProperties.GetParent(Object).OriginalValues;
+                _rootDictionary ??= (LinkedProperties.GetParent(Object)?.OriginalValueList ?? new OriginalValues());
                 return _rootDictionary;
             }
         }
@@ -85,7 +85,7 @@ namespace InABox.Core
 
         public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
         {
-            return RootDictionary.Where(x => x.Key.StartsWith(RootPath)).GetEnumerator();
+            return RootDictionary.Where(x => x.Key.StartsWith(RootPath)).Select(x => new KeyValuePair<string, object?>(x.Key[RootPath.Length..], x.Value)).GetEnumerator();
         }
 
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@@ -106,7 +106,7 @@ namespace InABox.Core
         {
             get
             {
-                _rootSet ??= LinkedProperties.GetParent(Object).LoadedColumns;
+                _rootSet ??= (LinkedProperties.GetParent(Object)?.LoadedColumns ?? new LoadedColumns());
                 return _rootSet;
             }
         }
@@ -140,6 +140,13 @@ namespace InABox.Core
         {
             return RootSet.Contains(ChangeKey(key));
         }
+
+        public IEnumerator<string> GetEnumerator()
+        {
+            return RootSet.Where(x => x.StartsWith(RootPath)).Select(x => x[RootPath.Length..]).GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
     }
 
     public static class LinkedProperties
@@ -171,7 +178,7 @@ namespace InABox.Core
             return filtered;
         }*/
 
-        public static BaseObject GetParent(ISubObject link)
+        public static BaseObject? GetParent(ISubObject link)
         {
             while (true)
             {
@@ -180,14 +187,14 @@ namespace InABox.Core
                 {
                     link = parentLink;
                 }
-                else
+                else 
                 {
                     return parent;
                 }
             }
         }
 
-        public static string GetPath(ISubObject link)
+        public static string? GetPath(ISubObject link)
         {
             var path = link.GetLinkedPath();
             while (true)
@@ -217,7 +224,7 @@ namespace InABox.Core
         public static IEnumerable<ILinkedProperty> Find(ISubObject subObject, out BaseObject parent)
         {
             parent = GetParent(subObject);
-            if (!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
+            if (parent is null || !_LinkedProperties.TryGetValue(parent.GetType(), out var props))
             {
                 return Enumerable.Empty<ILinkedProperty>();
             }
@@ -226,12 +233,13 @@ namespace InABox.Core
             return props.Where(x => x.Path == path);
         }
 
-        public static bool Find(ISubObject subObject, string name, [NotNullWhen(true)] out ILinkedProperty? property, out BaseObject parent)
+        public static bool Find(ISubObject subObject, string name, [NotNullWhen(true)] out ILinkedProperty? property, [NotNullWhen(true)] out BaseObject? parent)
         {
             property = null;
             parent = GetParent(subObject);
-            if (parent == null)
+            if (parent is null)
                 return false;
+
             if(!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
                 return false;
             var path = GetPath(subObject);

+ 68 - 2
InABox.Core/Serialization.cs

@@ -48,6 +48,7 @@ namespace InABox.Core
                 _serializerSettings.Converters.Add(new ColumnJsonConverter());
                 _serializerSettings.Converters.Add(new SortOrderJsonConverter());
                 _serializerSettings.Converters.Add(new UserPropertiesJsonConverter());
+                //_serializerSettings.Converters.Add(new BaseObjectJSONConverter());
 
                 _serializerSettings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
             }
@@ -664,7 +665,7 @@ namespace InABox.Core
             where TObject : BaseObject
         {
             var originalValues = new List<Tuple<Type, string, object?>>();
-            foreach (var (key, value) in obj.OriginalValues)
+            foreach (var (key, value) in obj.OriginalValueList)
             {
                 if (DatabaseSchema.Property(obj.GetType(), key) is IProperty prop)
                 {
@@ -696,7 +697,7 @@ namespace InABox.Core
                 if (DatabaseSchema.Property(obj.GetType(), key) is IProperty prop)
                 {
                     var value = reader.ReadBinaryValue(prop.PropertyType);
-                    obj.OriginalValues[prop.Name] = value;
+                    obj.OriginalValueList[prop.Name] = value;
                 }
             }
         }
@@ -862,4 +863,69 @@ namespace InABox.Core
             return objs;
         }
     }
+
+    public class BaseObjectJSONConverter : JsonConverter
+    {
+        public override bool CanConvert(Type objectType)
+        {
+            return objectType.IsSubclassOf(typeof(BaseObject));
+        }
+
+        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+        {
+            var obj = (Activator.CreateInstance(objectType) as BaseObject)!;
+            obj.SetObserving(false);
+
+            if (reader.TokenType == JsonToken.Null)
+                return null;
+
+            var data = JObject.Load(reader);
+
+            foreach(var (k, v) in data)
+            {
+                if (string.Equals(k, "OriginalValues") && v is JObject originalValues)
+                {
+                    foreach(var (origk, origv) in originalValues)
+                    {
+                        if (origv is null) continue;
+
+                        var property = DatabaseSchema.Property(objectType, origk);
+                        if (property is null) continue;
+
+                        obj.OriginalValueList[origk] = origv.ToObject(property.PropertyType);
+                    }
+                }
+                else if(DatabaseSchema.Property(objectType, k) is IProperty prop)
+                {
+                    prop.Setter()(obj, v?.ToObject(prop.PropertyType));
+                }
+            }
+            obj.SetObserving(true);
+            return obj;
+        }
+
+        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+        {
+            if (!(value is BaseObject obj)) return;
+
+            writer.WriteStartObject();
+
+            writer.WritePropertyName("OriginalValues");
+            writer.WriteStartObject();
+            foreach(var (k, v) in obj.OriginalValueList)
+            {
+                writer.WritePropertyName(k);
+                serializer.Serialize(writer, v);
+            }
+            writer.WriteEndObject();
+
+            foreach(var property in DatabaseSchema.Properties(obj.GetType()))
+            {
+                writer.WritePropertyName(property.Name);
+                serializer.Serialize(writer, property.Getter()(obj));
+            }
+
+            writer.WriteEndObject();
+        }
+    }
 }

+ 1 - 1
InABox.Database/DataUpdater.cs

@@ -236,7 +236,7 @@ public static class DataUpdater
 
         var result = DbFactory.NewProvider(Logger.Main).Query(new Filter<GlobalSettings>(x => x.Section).IsEqualTo(nameof(DatabaseVersion)))
             .Rows.FirstOrDefault()?.ToObject<GlobalSettings>() ?? new GlobalSettings() { Section = nameof(DatabaseVersion), Key = "" };
-        result.OriginalValues["Contents"] = result.Contents;
+        result.OriginalValueList["Contents"] = result.Contents;
         result.Contents = Serialization.Serialize(dbVersion);
         DbFactory.NewProvider(Logger.Main).Save(result);
     }