using System; using System.Collections.Generic; using System.Data; using System.Text; using Microsoft.Data.Sqlite; using Microsoft.Extensions.Configuration; using Microsoft.VisualBasic; using NLog; namespace ChaosBot.Database { public static class Controller { static SqliteConnection _conn = new SqliteConnection($"Data Source={System.IO.Directory.GetCurrentDirectory()}/{Program.Cfg.GetValue("Bot:Database")}"); private static Logger _logger = Program._logger; public static DataTable RawQuery(string query, bool readOutput = true, bool throwError = false) { DataTable dt = new DataTable(); try { using (_conn) { _conn.Open(); SqliteCommand cmd = _conn.CreateCommand(); cmd.CommandText = query; if (readOutput) { SqliteDataReader executeReader = cmd.ExecuteReader(CommandBehavior.SingleResult); dt.Load(executeReader); } else { cmd.ExecuteNonQuery(); } _conn.Close(); } } catch (Exception ex) { if (throwError) { throw; } _logger.Fatal($"Database.Controller.RawQuery: Exception [{ex}] thrown, <[{ex.Message}]>."); } return dt; } public static void InsertQuery(string table, Dictionary parameters) { try { using (_conn) { _conn.Open(); SqliteCommand cmd = _conn.CreateCommand(); StringBuilder commandText = new StringBuilder(); commandText.Append("INSERT INTO "); commandText.Append(table); commandText.Append(" ("); foreach (string key in parameters.Keys) { commandText.Append($"{key}, "); } commandText.Remove(commandText.Length - 2, 2); commandText.Append(") VALUES ("); foreach (string key in parameters.Keys) { commandText.Append($"@{key},"); } commandText.Remove(commandText.Length - 1, 1); commandText.Append(")"); cmd.CommandText = commandText.ToString(); foreach (string key in parameters.Keys) { cmd.Parameters.AddWithValue($"@{key}", parameters.GetValueOrDefault(key)); } cmd.Prepare(); cmd.ExecuteNonQuery(); _conn.Close(); } } catch (Exception ex) { _logger.Fatal($"Database.Controller.InsertQuery: Exception [{ex}] thrown, <[{ex.Message}]>."); } } public static void UpdateQuery(string table, Dictionary values, Dictionary parameters) { try { using (_conn) { _conn.Open(); SqliteCommand cmd = _conn.CreateCommand(); StringBuilder commandText = new StringBuilder(); commandText.Append("UPDATE "); commandText.Append(table); commandText.Append(" SET "); List updateList = new List(); foreach (string key in values.Keys) { updateList.Add($"{key}=@val_{key} "); cmd.Parameters.AddWithValue($@"val_{key}", values.GetValueOrDefault(key)); } commandText.Append(string.Join(", ", updateList)); List filterList = new List(); foreach (string key in parameters.Keys) { filterList.Add($"{key}=@fil_{key} "); cmd.Parameters.AddWithValue($"@fil_{key}", parameters.GetValueOrDefault(key)); } if (filterList.Count > 0) { commandText.Append("WHERE "); commandText.Append(string.Join("AND ", filterList)); } cmd.CommandText = commandText.ToString(); Console.WriteLine(commandText.ToString()); cmd.Prepare(); cmd.ExecuteNonQuery(); _conn.Close(); } } catch (Exception ex) { _logger.Fatal($"Database.Controller.UpdateQuery: Exception [{ex}] thrown, <[{ex.Message}]>."); } } public static int TransactionQuery(List cmds) { SqliteCommand command = _conn.CreateCommand(); SqliteTransaction transaction; _conn.Open(); // Start a local transaction. transaction = _conn.BeginTransaction(); // Must assign both transaction object and connection // to Command object for a pending local transaction command.Connection = _conn; command.Transaction = transaction; try { foreach (var cmd in cmds) { command.CommandText = cmd.CommandText; command.ExecuteNonQuery(); } // Attempt to commit the transaction. transaction.Commit(); _logger.Info($"{cmds.Count} record(s) are written to database."); } catch (Exception ex) { _logger.Warn("Commit Exception Type: {0}", ex.GetType()); _logger.Warn(" Message: {0}", ex.Message); // Attempt to roll back the transaction. try { transaction.Rollback(); } catch (Exception ex2) { // This catch block will handle any errors that may have occurred // on the server that would cause the rollback to fail, such as // a closed connection. _logger.Warn("Rollback Exception Type: {0}", ex2.GetType()); _logger.Warn(" Message: {0}", ex2.Message); } return 0; } _conn.Close(); return cmds.Count; } public static DataTable SelectQuery(string table, string selectColumns = "*", Dictionary filterColumns = null, string orderByKey = null) { DataTable dt = new DataTable(); try { using (_conn) { _conn.Open(); SqliteCommand cmd = _conn.CreateCommand(); string filter = null; if (filterColumns != null) { List filterList = new List(); foreach (string key in filterColumns.Keys) { filterList.Add($"{key} = @{key}"); } filter = $"WHERE {Strings.Join(filterList.ToArray(), " AND ")}"; foreach (string key in filterColumns.Keys) { cmd.Parameters.AddWithValue($@"{key}", filterColumns.GetValueOrDefault(key)); } } string order = null; if (orderByKey != null) { order = $"ORDER BY {orderByKey}"; } string query = $"SELECT {selectColumns} FROM {table} {filter} {order}"; cmd.CommandText = query; cmd.Prepare(); SqliteDataReader executeReader = cmd.ExecuteReader(); dt.Load(executeReader); _conn.Close(); } } catch (Exception ex) { _logger.Fatal($"Database.Controller.SelectQuery: Exception [{ex}] thrown, <[{ex.Message}]>."); } return dt; } public static void DeleteQuery(string table, Dictionary filterColumns = null, string orderByKey = null, int limit = -1, int offset = -1) { try { using (_conn) { _conn.Open(); SqliteCommand cmd = _conn.CreateCommand(); string filter = null; if (filterColumns != null) { List filterList = new List(); foreach (string key in filterColumns.Keys) { filterList.Add($"{key} = @{key}"); } filter = $"WHERE {Strings.Join(filterList.ToArray(), " AND ")}"; foreach (string key in filterColumns.Keys) { cmd.Parameters.AddWithValue($@"{key}", filterColumns.GetValueOrDefault(key)); } } string order = null; if (orderByKey != null) { order = $"ORDER BY {orderByKey}"; } string limitString = limit > 0 ? $"LIMIT {limit}" : null; string offsetString = offset > 0 ? $"OFFSET {offset}" : null; string query = $"DELETE FROM {table} {filter} {order} {limitString} {offsetString}"; cmd.CommandText = query; cmd.Prepare(); cmd.ExecuteNonQuery(); _conn.Close(); } } catch (Exception ex) { _logger.Fatal($"Database.Controller.DeleteQuery: Exception [{ex}] thrown, <[{ex.Message}]>."); } } } }