context: using System;
  using System.Collections.Generic;
  using System.Data;
  using System.Data.SQLite;
  using System.Text;
  
  namespace DarkMouse.Data
  {
      public class DB : IDisposable
      {
          static Dictionary<string, string> ConnectionStrings = new Dictionary<string, string>();
          static string DefaultDB = "DEFAULT";
  
          public static void Initialize(string connectionString)
          {
              ConnectionStrings[DefaultDB] = connectionString;
          }
  
          public static void AddDataSource(string sourceName, string connectionString)
          {
              ConnectionStrings[sourceName] = connectionString;
          }
  
          public static object ConvertNullable(object value)
          {
              if (value == null)
              {
                  return DBNull.Value;
              }
              return value;
          }
  
          string ConnectionString;
          SQLiteConnection Connection;
          SQLiteTransaction Transaction;
  
          public DB()
          {
              ConnectionString = ConnectionStrings[DefaultDB];
              Connection = new SQLiteConnection(ConnectionString);
              Connection.Open();
          }
  
          public DB(string sourceName)
          {
              ConnectionString = ConnectionStrings[sourceName];
              Connection = new SQLiteConnection(ConnectionString);
              Connection.Open();
          }
  
          public void BeginTransaction()
          {
              Transaction = Connection.BeginTransaction();
          }
  
          public void Commit()
          {
              Transaction.Commit();
              Transaction.Dispose();
              Transaction = null;
          }
  
          public void Rollback()
          {
              Transaction.Rollback();
              Transaction.Dispose();
              Transaction = null;
          }
  
          public int Execute(string sql)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  cmd.CommandText = sql;
                  return cmd.ExecuteNonQuery();
              }
          }
  
          public object GetData(string sql)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  cmd.CommandText = sql;
                  return cmd.ExecuteScalar();
              }
          }
  
          public object GetData(string table, string expression, Filter filter)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  StringBuilder sb = new StringBuilder();
                  sb.Append("SELECT " + expression + " FROM [" + table + "]");
                  string query = Filter.GetQuery(cmd, filter);
                  if (query.Length > 0)
                  {
                      sb.Append(" WHERE " + query);
                  }
                  cmd.CommandText = sb.ToString();
                  return cmd.ExecuteScalar();
              }
          }
  
          public DataTable GetTable(string sql)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  cmd.CommandText = sql;
                  SQLiteDataReader reader = cmd.ExecuteReader();
                  DataTable result = new DataTable();
                  result.Load(reader);
                  reader.Close();
                  return result;
              }
          }
  
          public DataTable GetTable(string table, Filter filter, Pagination pagination, Sort sort)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  string query = Filter.GetQuery(cmd, filter);
                  StringBuilder sb = new StringBuilder();
                  sb.Append("SELECT * FROM [" + table + "]");
                  if (query.Length > 0)
                  {
                      sb.Append(" WHERE " + query);
                  }
                  if (sort == null)
                  {
                      sb.Append(" ORDER BY [ID] ASC");
                  }
                  else
                  {
                      sb.Append(" " + sort.GetSortString());
                  }
                  if (pagination != null)
                  {
                      sb.Append(" LIMIT ").Append(pagination.PageSize * (pagination.PageNumber - 1)).Append(", ").Append(pagination.PageSize);
                  }
  
                  cmd.CommandText = sb.ToString();
                  SQLiteDataReader reader = cmd.ExecuteReader();
                  DataTable result = new DataTable();
                  result.Load(reader);
                  reader.Close();
                  return result;
              }
          }
  
          public string Insert(string table, Dictionary<string, object> fields)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  StringBuilder sb = new StringBuilder();
                  StringBuilder values = new StringBuilder();
                  sb.Append("INSERT INTO [" + table + "] (");
                  values.Append(" VALUES (");
                  foreach (KeyValuePair<string, object> kv in fields)
                  {
                      if (cmd.Parameters.Count > 0)
                      {
                          sb.Append(", ");
                          values.Append(", ");
                      }
                      sb.Append("[" + kv.Key + "]");
                      values.Append("@P" + cmd.Parameters.Count);
                      cmd.Parameters.Add(new SQLiteParameter("@P" + cmd.Parameters.Count, ConvertNullable(kv.Value)));
                  }
                  sb.Append(")");
                  values.Append(")");
                  sb.Append(values.ToString());
                  sb.Append("; SELECT LAST_INSERT_ROWID() AS Id");
                  cmd.CommandText = sb.ToString();
                  return cmd.ExecuteScalar().ToString();
              }
          }
  
          public int Update(string table, Dictionary<string, object> fields, Filter filter)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
                  StringBuilder sb = new StringBuilder();
                  sb.Append("UPDATE [" + table + "] SET ");
                  foreach (KeyValuePair<string, object> kv in fields)
                  {
                      if (cmd.Parameters.Count > 0)
                      {
                          sb.Append(", ");
                      }
                      sb.Append("[" + kv.Key + "] = @P" + cmd.Parameters.Count);
                      cmd.Parameters.Add(new SQLiteParameter("@P" + cmd.Parameters.Count, ConvertNullable(kv.Value)));
                  }
                  string query = Filter.GetQuery(cmd, filter);
                  if (query.Length > 0)
                  {
                      sb.Append(" WHERE " + query);
                  }
                  cmd.CommandText = sb.ToString();
                  return cmd.ExecuteNonQuery();
              }
          }
  
          public int Delete(string table, Filter filter)
          {
              using (SQLiteCommand cmd = GetDbCommand())
              {
  
gt:                 StringBuilder sb = new StringBuilder();