Преглед изворни кода

Added to 8.58 script to update CoreFilterDefinitions

Kenric Nugteren пре 1 недеља
родитељ
комит
01ce2fff8b
1 измењених фајлова са 223 додато и 33 уклоњено
  1. 223 33
      prs.shared/Database Update Scripts/Update_8_58.cs

+ 223 - 33
prs.shared/Database Update Scripts/Update_8_58.cs

@@ -29,7 +29,7 @@ internal class Update_8_58 : DatabaseUpdateScript
                 .Add(x => x.Processed)
                 .Add(x => x.Posted))
             .ToArray<TimeSheet>();
-        if(timeSheets.Length == 0)
+        if (timeSheets.Length == 0)
         {
             Logger.Send(LogType.Information, "", $"Migrating TimeSheet.Processed -> TimeSheet.Posted: Done");
             return;
@@ -63,7 +63,7 @@ internal class Update_8_58 : DatabaseUpdateScript
                 .Add(toColumn) // The order here matters a lot; since I've made a lot of obsolete links just point directly to the new one, then we have to set the new before the old.
                 .Add(fromColumn))
             .ToArray<T>();
-        if(items.Length == 0)
+        if (items.Length == 0)
         {
             return;
         }
@@ -145,9 +145,9 @@ internal class Update_8_58 : DatabaseUpdateScript
 
         var variables = new List<DigitalFormVariable>();
         var layouts = new List<DigitalFormLayout>();
-        foreach(var item in qaQuestions)
+        foreach (var item in qaQuestions)
         {
-            if(formSequences.TryGetValue(item.FormID, out var sequence))
+            if (formSequences.TryGetValue(item.FormID, out var sequence))
             {
                 sequence++;
             }
@@ -178,12 +178,12 @@ internal class Update_8_58 : DatabaseUpdateScript
             var nButtons = 0;
 
             var i = 1;
-            foreach(var question in item.Questions)
+            foreach (var question in item.Questions)
             {
                 layout.RowHeights.Add("Auto");
                 var row = layout.RowHeights.Count;
 
-                if(question.Answer == QAAnswer.Comment)
+                if (question.Answer == QAAnswer.Comment)
                 {
                     var label = new DFLayoutLabel { Caption = question.Question, Row = row, Column = 1, ColumnSpan = 3 };
                     label.Style.HorizontalTextAlignment = DFLayoutAlignment.Middle;
@@ -225,7 +225,7 @@ internal class Update_8_58 : DatabaseUpdateScript
                                 optionProperties.Options = DFLayoutOptionFieldProperties.WriteOptions(buttons);
 
                                 var colourExpression = "null";
-                                foreach(var (option, colour) in buttons.Zip(colors))
+                                foreach (var (option, colour) in buttons.Zip(colors))
                                 {
                                     colourExpression = $"If([{code}] == {QuoteString(option)}, {QuoteString(colour)}, {colourExpression})";
                                 }
@@ -319,7 +319,7 @@ internal class Update_8_58 : DatabaseUpdateScript
 
                 var values = DigitalForm.DeserializeFormSaveData(instance) ?? new();
                 var items = values.ToLoadStorage().Items().ToArray();
-                foreach(var (key, value) in items)
+                foreach (var (key, value) in items)
                 {
                     if (!Guid.TryParse(key, out var id)) continue;
                     if (!mappings.TryGetValue(id, out var code)) continue;
@@ -333,8 +333,23 @@ internal class Update_8_58 : DatabaseUpdateScript
             filter: Filter<DigitalForm>.Where(x => x.ID).InList(qaQuestions.ToArray(x => x.FormID)));
     }
 
-    private class ExtraMap<TFrom, TTo>
+    private interface IExtraMap
     {
+        public Type TFrom { get; }
+        public Type TTo { get; }
+
+        IProperty From { get; }
+
+        IProperty To { get; }
+
+        Func<object?, object?>? Map { get; }
+    }
+
+    private class ExtraMap<TFrom, TTo> : IExtraMap
+    {
+        Type IExtraMap.TFrom => typeof(TFrom);
+        Type IExtraMap.TTo => typeof(TTo);
+
         public IProperty From { get; }
 
         public IProperty To { get; }
@@ -376,20 +391,20 @@ internal class Update_8_58 : DatabaseUpdateScript
 
         var maps = new List<(IProperty from, IProperty to, Func<object?, object?>? map)>();
 
-        foreach(var map in extraMaps ?? [])
+        foreach (var map in extraMaps ?? [])
         {
             currentMaps.Add(map.From.Name);
 
             maps.Add((map.From, map.To, map.Map));
         }
 
-        foreach(var fromProperty in DatabaseSchema.LocalProperties(typeof(TFrom)))
+        foreach (var fromProperty in DatabaseSchema.LocalProperties(typeof(TFrom)))
         {
             if (currentMaps.Contains(fromProperty.Name)) continue;
 
-            if(DatabaseSchema.Property(typeof(TTo), fromProperty.Name) is IProperty toProperty)
+            if (DatabaseSchema.Property(typeof(TTo), fromProperty.Name) is IProperty toProperty)
             {
-                if(fromProperty.PropertyType != toProperty.PropertyType)
+                if (fromProperty.PropertyType != toProperty.PropertyType)
                 {
                     throw new Exception($"Cannot migrate {typeof(TFrom).Name}.{fromProperty.Name} -> {typeof(TTo).Name}.{toProperty.Name}: type mismatch");
                 }
@@ -421,9 +436,9 @@ internal class Update_8_58 : DatabaseUpdateScript
                     var newItem = new TTo();
                     newItem.SetObserving(false);
                     newItem.ID = item.ID;
-                    foreach(var (from, to, map) in maps)
+                    foreach (var (from, to, map) in maps)
                     {
-                        if(map is not null)
+                        if (map is not null)
                         {
                             to.Setter()(newItem, map(from.Getter()(item)));
                         }
@@ -462,7 +477,7 @@ internal class Update_8_58 : DatabaseUpdateScript
                 && x.IsGenericMethod
                 && x.GetGenericArguments().Length == 1)
             .First();
-        foreach(var entity in DbFactory.ProviderFactory.Types.Where(x => x.HasInterface(typeof(IEntityDocument))))
+        foreach (var entity in DbFactory.ProviderFactory.Types.Where(x => x.HasInterface(typeof(IEntityDocument))))
         {
             var entityMethod = method.MakeGenericMethod(entity);
 
@@ -475,10 +490,10 @@ internal class Update_8_58 : DatabaseUpdateScript
             entityMethod.Invoke(null, [provider, documentFromProp.Name, documentToProp.Name]);
         }
 
-        foreach(var entity in DbFactory.ProviderFactory.Types)
+        foreach (var entity in DbFactory.ProviderFactory.Types)
         {
             MethodInfo? entityMethod = null;
-            foreach(var property in DatabaseSchema.LocalProperties(entity))
+            foreach (var property in DatabaseSchema.LocalProperties(entity))
             {
                 if (property.Parent is null
                     || property.Parent.PropertyType != typeof(LocalityLink)
@@ -567,6 +582,191 @@ internal class Update_8_58 : DatabaseUpdateScript
         RenameTable<RequisitionKanban, PickingListKanban>(provider);
     }
 
+    private static Dictionary<Type, Dictionary<string, IExtraMap>> _filterMaps = [];
+
+    private static IExtraMap[] GetFilterMaps()
+    {
+        return new IExtraMap[]
+        {
+            new ExtraMap<Kanban, Kanban>(DatabaseSchema.PropertyStrict(typeof(Kanban), "Category"), DatabaseSchema.PropertyStrict<Kanban>(x => x.Status))
+            {
+                Map = x =>
+                {
+                    if(x is string category)
+                    {
+                        if (String.IsNullOrWhiteSpace(category) || category.Equals("Open"))
+                            return KanbanStatus.Open;
+                        if(category.Equals("In Progress"))
+                            return KanbanStatus.InProgress;
+                        if (category.Equals("Waiting"))
+                            return KanbanStatus.Waiting;
+                        if (category.Equals("Complete"))
+                            return KanbanStatus.Complete;
+                        return KanbanStatus.Open;
+                    }
+                    else
+                    {
+                        return KanbanStatus.Open;
+                    }
+                }
+            }
+        };
+    }
+
+    private static bool CheckFilter(IFilter filter, Dictionary<string, IExtraMap>? maps)
+    {
+        var changed = false;
+        if(maps is not null && maps.TryGetValue(filter.Property, out var map))
+        {
+            filter.Property = map.To.Name;
+            var value = map.Map?.Invoke(filter.Value);
+            if(value is null)
+            {
+                filter.Value = null;
+                changed = true;
+            }
+            else if (filter.Type.IsAssignableFrom(value.GetType()))
+            {
+                filter.Value = value;
+                changed = true;
+            }
+        }
+        if (!changed)
+        {
+            var columnName = ConvertColumnName(filter.Type, filter.Property);
+            if(columnName is not null)
+            {
+                filter.Property = columnName;
+                changed = true;
+            }
+        }
+        foreach(var and in filter.Ands)
+        {
+            changed = CheckFilter(and, maps) || changed;
+        }
+        foreach(var or in filter.Ors)
+        {
+            changed = CheckFilter(or, maps) || changed;
+        }
+        return changed;
+    }
+
+    private static void UpdateFilters<T>(IProvider provider)
+        where T : Entity, IDatabaseStoredSettings, new()
+    {
+        var settings = provider.Query(
+            Filter<T>.Where(x => x.Section).IsEqualTo(nameof(CoreFilterDefinitions)),
+            Columns.None<T>()
+                .Add(x => x.ID)
+                .Add(x => x.Key)
+                .Add(x => x.Contents))
+            .ToArray<T>();
+
+        var changedSettings = new List<T>();
+        foreach(var setting in settings)
+        {
+            if (setting.Key.IsNullOrWhiteSpace()) continue;
+
+            var entityName = setting.Key.Split('.')[^1];
+            var entity = CoreUtils.Entities.Where(x => x.Name == entityName
+                && x.IsSubclassOf(typeof(Entity)))
+                .FirstOrDefault();
+
+            var filters = Serialization.Deserialize<CoreFilterDefinitions>(setting.Contents);
+            if(filters is not null)
+            {
+                var changed = false;
+                foreach(var filter in filters)
+                {
+                    var deserialiseEntity = entity is not null ? typeof(Filter<>).MakeGenericType(entity) : typeof(IFilter);
+                    IFilter? deserialised = null;
+                    try
+                    {
+                        deserialised = (Serialization.Deserialize(deserialiseEntity, filter.Filter, strict: true) as IFilter)!;
+                        if(deserialised is null)
+                        {
+                            continue;
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        var dict = Serialization.Deserialize<Dictionary<string, object?>>(filter.Filter) ?? [];
+                        if (dict.TryGetValue("Expression", out var expression) && expression is string str)
+                        {
+                            try
+                            {
+                                var exp = CoreUtils.StringToExpression(str);
+                                if(exp is MemberExpression memExp)
+                                {
+                                    deserialiseEntity = memExp.Expression?.Type;
+                                    if(deserialiseEntity is not null)
+                                    {
+                                        deserialiseEntity = typeof(Filter<>).MakeGenericType(deserialiseEntity);
+                                        deserialised = (Serialization.Deserialize(deserialiseEntity, filter.Filter, strict: true) as IFilter)!;
+                                    }
+                                }
+                            }
+                            catch(Exception)
+                            {
+                            }
+                        }
+                        if(deserialised is null)
+                        {
+                            Logger.Send(LogType.Error, "", $"Error in deserialising filter '{filter.Name}' of {setting.Key}: {CoreUtils.FormatException(e)}");
+                            continue;
+                        }
+                    }
+
+                    var type = deserialised.GetType().GetSuperclassDefinition(typeof(Filter<>))!.GenericTypeArguments[0];
+                    if (CheckFilter(deserialised, _filterMaps.GetValueOrDefault(type)))
+                    {
+                        filter.Filter = Serialization.Serialize(deserialised);
+                        changed = true;
+                    }
+                }
+                if (changed)
+                {
+                    setting.Contents = Serialization.Serialize(filters);
+                    changedSettings.Add(setting);
+                }
+            }
+        }
+
+        provider.Save(changedSettings);
+    }
+    private static void UpdateFilters(IProvider provider)
+    {
+        _filterMaps = GetFilterMaps()
+            .GroupBy(x => x.TFrom)
+            .ToDictionary(x => x.Key, x => x.ToDictionary(x => x.From.Name));
+
+        UpdateFilters<GlobalSettings>(provider);
+        UpdateFilters<UserSettings>(provider);
+    }
+
+    private static string? ConvertColumnName(Type entity, string originalColumnName)
+    {
+        var i = 0;
+        var changed = false;
+        while(i < originalColumnName.Length)
+        {
+            var index = originalColumnName.IndexOf("Link.", i);
+            if (index == -1) break;
+
+            var columnName = originalColumnName[0..index];
+            if(DatabaseSchema.Property(entity, columnName) is IProperty property)
+            {
+                originalColumnName = $"{property.Name}.{originalColumnName[(index + 5)..]}";
+                changed = true;
+            }
+            else
+            {
+                i = index + 5;
+            }
+        }
+        return changed ? originalColumnName : null;
+    }
+
     private static void UpdateColumns<T>(IProvider provider)
         where T : Entity, IDatabaseStoredSettings, new()
     {
@@ -595,22 +795,11 @@ internal class Update_8_58 : DatabaseUpdateScript
                 var changed = false;
                 foreach(var column in columns)
                 {
-                    var i = 0;
-                    while(i < column.ColumnName.Length)
+                    var columnName = ConvertColumnName(entity, column.ColumnName);
+                    if(columnName is not null)
                     {
-                        var index = column.ColumnName.IndexOf("Link.", i);
-                        if (index == -1) break;
-
-                        var columnName = column.ColumnName[0..index];
-                        if(DatabaseSchema.Property(entity, columnName) is IProperty property)
-                        {
-                            column.ColumnName = $"{property.Name}.{column.ColumnName[(index + 5)..]}";
-                            changed = true;
-                        }
-                        else
-                        {
-                            i = index + 5;
-                        }
+                        column.ColumnName = columnName;
+                        changed = true;
                     }
                 }
                 if (changed)
@@ -736,6 +925,7 @@ internal class Update_8_58 : DatabaseUpdateScript
         UpdateTimeSheets(provider);
 
         ConvertLinks(provider);
+        UpdateFilters(provider);
         UpdateColumns(provider);
 
         UpdateSecurityTokens(provider);