Просмотр исходного кода

Added default values for columns in DB

Kenric Nugteren 1 месяц назад
Родитель
Сommit
4eb08eee92
1 измененных файлов с 153 добавлено и 77 удалено
  1. 153 77
      inabox.database.sqlite/SQLiteProvider.cs

+ 153 - 77
inabox.database.sqlite/SQLiteProvider.cs

@@ -464,6 +464,8 @@ public class SQLiteProviderFactory : IProviderFactory
 
     #region Database Structure Management
 
+    #region MetaData
+
     private class MetadataEntry
     {
         public String Name { get; set; }
@@ -485,6 +487,124 @@ public class SQLiteProviderFactory : IProviderFactory
             Triggers = new List<MetadataEntry>();
         }
     }
+
+    // Skipped starting '[' already
+    private void ParseField(string sql, ref int i, Dictionary<string, string> fields)
+    {
+        var j = i;
+        while(j < sql.Length)
+        {
+            if (sql[j] == ']')
+            {
+                break;
+            }
+            ++j;
+        }
+
+        var fieldName = sql[i..j];
+
+        ++j;
+        while(j < sql.Length && char.IsWhiteSpace(sql[j]))
+        {
+            ++j;
+        }
+
+        i = j;
+
+        while(i < sql.Length)
+        {
+            if (sql[i] == '\'')
+            {
+                while(i < sql.Length && sql[i] != '\'')
+                {
+                    ++i;
+                }
+                ++i;
+            }
+            else if (sql[i] == ',')
+            {
+                break;
+            }
+            else if (sql[i] == ')')
+            {
+                break;
+            }
+            else
+            {
+                ++i;
+            }
+        }
+
+        fields[fieldName] = sql[j..i].Trim();
+    }
+
+    private Dictionary<string, string> ParseTableMetadata(string table, string sql, bool isTable)
+    {
+        var tableFields = new Dictionary<string, string>();
+
+        if (isTable)
+        {
+            var i = sql.IndexOf('(') + 1;
+            if(i == 0)
+            {
+                throw new Exception($"Expected 'CREATE TABLE {table} ('");
+            }
+
+            while (i < sql.Length)
+            {
+                var c = sql[i];
+                if (Char.IsWhiteSpace(c))
+                {
+                    ++i;
+                }
+                else if(c == ')')
+                {
+                    break;
+                }
+                else if(c == '[')
+                {
+                    ++i;
+                    ParseField(sql, ref i, tableFields);
+                }
+                else
+                {
+                    ++i;
+                }
+            }
+        }
+        else
+        {
+            sql = sql.Replace("\"", "")
+                .Replace("DISTINCT ", "");
+            sql = sql.Split(new String[] { " AS SELECT " }, StringSplitOptions.TrimEntries).Last();
+            sql = sql.Split(new String[] { " FROM " }, StringSplitOptions.TrimEntries).First();
+
+            var fields = sql.Replace("\n\t", "").Replace("\t", " ").Replace("\"", "").Trim().Split(',');
+            foreach (var fld in fields)
+            {
+                var field = fld.Trim()
+                    .Replace("\t", " ")
+                    .Replace("\"", "")
+                    .Replace("[", "").Replace("]", "");
+
+                var parts = field.Split(" as ");
+                if(parts.Length == 1)
+                {
+                    tableFields[field] = "";
+                }
+                else if(parts.Length == 2)
+                {
+                    field = parts[1];
+                    if (parts[0] != "NULL")
+                    {
+                        tableFields[field] = "";
+                    }
+                }
+            }
+        }
+
+        return tableFields;
+    }
     
     private Dictionary<string, Tuple<Dictionary<string, string>, Dictionary<string, string>, Dictionary<string, string>>> LoadMetaData()
     {
@@ -505,77 +625,18 @@ public class SQLiteProviderFactory : IProviderFactory
                     if (reader.HasRows)
                         while (reader.Read())
                         {
-                            var tblinfo = new Tuple<Dictionary<string, string>, Dictionary<string, string>, Dictionary<string, string>>(
-                                new Dictionary<string, string>(), new Dictionary<string, string>(), new Dictionary<string, string>());
-
                             var table = reader.GetString(0);
                             var sql = reader.GetString(1);
-                            bool istable = String.Equals(reader.GetString(2),"table");
+                            var istable = String.Equals(reader.GetString(2),"table");
 
-                            if (istable)
+                            try
                             {
-                                sql = sql.Replace("\"", "")
-                                    .Replace(string.Format("CREATE TABLE {0} (", table), "");
-                                sql = sql.Remove(sql.Length - 1).Trim();
-                                var fields = sql.Replace("\n\t", "").Replace("\t", " ").Replace("\"", "").Trim().Split(',');
-                                var primarykey = "";
-                                foreach (var fld in fields)
-                                {
-                                    var field = fld.Trim().Replace("\t", " ").Replace("\"", "").Replace("[", "").Replace("]", "");
-                                    //if (field.ToUpper().StartsWith("CONSTRAINT"))
-                                    //    tblinfo.Item2.Add(field);
-                                    if (field.ToUpper().StartsWith("PRIMARY KEY"))
-                                    {
-                                        primarykey = field.Replace("PRIMARY KEY(", "").Replace(")", "");
-                                    }
-                                    else
-                                    {
-                                        var comps = field.Split(' ');
-
-                                        tblinfo.Item1[comps[0]] = string.Format("{0}{1}", comps[1],
-                                            field.Contains("PRIMARY KEY") ? " PRIMARY KEY" : "");
-                                    }
-                                }
-
-                                if (!string.IsNullOrEmpty(primarykey))
-                                {
-                                    var pkfld = tblinfo.Item1[primarykey];
-                                    if (!pkfld.ToUpper().Contains("PRIMARY KEY"))
-                                        tblinfo.Item1[primarykey] = string.Format("{0} PRIMARY KEY", pkfld.Trim());
-                                }
+                                metadata[table] = new(ParseTableMetadata(table, sql, istable), new(), new());
                             }
-                            else
+                            catch(Exception e)
                             {
-                                sql = sql.Replace("\"", "")
-                                    .Replace("DISTINCT ", "");
-                                sql = sql.Split(new String[] { " AS SELECT " }, StringSplitOptions.TrimEntries).Last();
-                                sql = sql.Split(new String[] { " FROM " }, StringSplitOptions.TrimEntries).First();
-
-                                var fields = sql.Replace("\n\t", "").Replace("\t", " ").Replace("\"", "").Trim().Split(',');
-                                foreach (var fld in fields)
-                                {
-                                    var field = fld.Trim()
-                                        .Replace("\t", " ")
-                                        .Replace("\"", "")
-                                        .Replace("[", "").Replace("]", "");
-
-                                    var parts = field.Split(" as ");
-                                    if(parts.Length == 1)
-                                    {
-                                        tblinfo.Item1[field] = "";
-                                    }
-                                    else if(parts.Length == 2)
-                                    {
-                                        field = parts[1];
-                                        if (parts[0] != "NULL")
-                                        {
-                                            tblinfo.Item1[field] = "";
-                                        }
-                                    }
-                                }
+                                Log(LogType.Error, $"Invalid table metadata for {table}: {CoreUtils.FormatException(e)}");
                             }
-
-                            metadata[table] = tblinfo;
                         }
 
                     reader.Close();
@@ -622,6 +683,8 @@ public class SQLiteProviderFactory : IProviderFactory
         return metadata;
     }
 
+    #endregion
+
     private static void LoadType(Type type, List<Type> into)
     {
         if (into.Contains(type))
@@ -684,6 +747,12 @@ public class SQLiteProviderFactory : IProviderFactory
         return "TEXT";
     }
 
+    /// <summary>
+    /// For the given <paramref name="type"/>, load all the fields for the corresponding DB table, populating
+    /// <paramref name="fields"/> with entries <c>'fieldName': 'SQL definition'</c>, e.g., <c>"Description": "TEXT"</c>
+    /// </summary>
+    /// <param name="type"></param>
+    /// <param name="fields"></param>
     private void LoadFields(Type type, Dictionary<string, string> fields)
     {
         AutoEntity? view = type.GetCustomAttribute<AutoEntity>();
@@ -693,9 +762,11 @@ public class SQLiteProviderFactory : IProviderFactory
 
         foreach(var property in DatabaseSchema.Properties(definition).Where(x => x.IsDBColumn))
         {
+            var defaultValue = SQLiteProvider.EscapeValue(SQLiteProvider.GetColumnDefaultValue(property.PropertyType));
             fields[property.Name] =
                 ColumnType(property.PropertyType)
-                + (property.Name.Equals("ID") ? " PRIMARY KEY" : "");
+                + (property.Name.Equals("ID") ? " PRIMARY KEY" : "")
+                + $" DEFAULT {defaultValue}";
         }
     }
 
@@ -782,7 +853,7 @@ public class SQLiteProviderFactory : IProviderFactory
             {
                 foreach(var field in fields)
                 {
-                    actions.Add($"UPDATE {otherType.Name} SET [{field}] = NULL WHERE [{field}] = old.ID;");
+                    actions.Add($"UPDATE {otherType.Name} SET [{field}] = '{Guid.Empty}' WHERE [{field}] = old.ID;");
                 }
             }
         }
@@ -1269,13 +1340,19 @@ public class SQLiteProviderFactory : IProviderFactory
                 Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
             }
 
-            if (!current_fields.ContainsKey(field) || (!String.IsNullOrWhiteSpace(current_fields[field])) && (current_fields[field] != type_fields[field]))
+            if (!current_fields.TryGetValue(field, out string? value) || (!String.IsNullOrWhiteSpace(value)) && (value != type_fields[field]))
                 bRebuild = true;
         }
 
-        foreach (var field in current_fields.Keys)
-            if (!type_fields.ContainsKey(field))
-                bRebuild = true;
+        if (!bRebuild)
+        {
+            foreach (var field in current_fields.Keys)
+                if (!type_fields.ContainsKey(field))
+                {
+                    bRebuild = true;
+                    break;
+                }
+        }
 
         if (bForceRebuild || bRebuild)
             RebuildTable(access, type, current_fields, type_fields, customproperties);
@@ -1949,7 +2026,7 @@ public class SQLiteProvider : IProvider
         return sParam;
     }
 
-    private static object? GetFilterDefaultValue(Type type)
+    internal static object? GetColumnDefaultValue(Type type)
     {
         if(type == typeof(string))
         {
@@ -2096,7 +2173,7 @@ public class SQLiteProvider : IProvider
                     }
                     else
                     {
-                        var strProp = $"IFNULL({prop},{EscapeValue(GetFilterDefaultValue(filter.Type))})";
+                        var strProp = $"IFNULL({prop},{EscapeValue(GetColumnDefaultValue(filter.Type))})";
                         value = useparams ? EncodeParameter(command, value) : EscapeValue(filter.Value);
                         result = string.Format("(" + operators[filter.Operator] + ")", strProp, value);
                     }
@@ -2104,9 +2181,9 @@ public class SQLiteProvider : IProvider
             }
             else
             {
-                var strProp = $"IFNULL({prop},{EscapeValue(GetFilterDefaultValue(filter.Type))})";
+                var strProp = $"IFNULL({prop},{EscapeValue(GetColumnDefaultValue(filter.Type))})";
                 var strValue = filter.Value is FilterConstant constant
-                    ? constant == FilterConstant.Null ? EscapeValue(GetFilterDefaultValue(filter.Type)) : GetFilterConstant(constant)
+                    ? constant == FilterConstant.Null ? EscapeValue(GetColumnDefaultValue(filter.Type)) : GetFilterConstant(constant)
                     : useparams ? EncodeParameter(command, Encode(filter.Value, filter.Type, convertToNull: false)) : EscapeValue(filter.Value);
 
                 result = string.Format($"({operators[filter.Operator]})", strProp, strValue);
@@ -3053,13 +3130,11 @@ public class SQLiteProvider : IProvider
         var insertvalues = new List<string>();
         var updatecommands = new List<string>();
 
-        var iParam = 0;
         foreach (var (key, v) in insert)
         {
             if (v is UserProperties)
                 continue;
 
-            var sParam = string.Format("@p{0}", iParam++);
             object? value = null;
             try
             {
@@ -3070,7 +3145,8 @@ public class SQLiteProvider : IProvider
                 Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
             }
 
-            command.Parameters.AddWithValue(sParam, value);
+
+            var sParam = EncodeParameter(command, value);
 
             insertfields.Add(string.Format("[{0}]", key));