New SqlDatabase functions

This commit is contained in:
2023-11-07 10:13:22 +02:00
parent 692f3d8f8c
commit 1f0e6516fd
4 changed files with 215 additions and 56 deletions

View File

@@ -85,7 +85,7 @@ public class Boot
await commandServiceHandler.InstallCommandsAsync(); await commandServiceHandler.InstallCommandsAsync();
Config._DiscordBotClient = this; Config.DiscordBotClient = this;
while (!isReady) ; while (!isReady) ;
} }

View File

@@ -13,9 +13,9 @@ public class Config
public static Logger Logger; public static Logger Logger;
public static SettingsDictionary<string, string> AppSettings; public static SettingsDictionary<string, string> AppSettings;
internal static Boot? _DiscordBotClient; internal static Boot? DiscordBotClient;
public static Boot? DiscordBot => _DiscordBotClient; public static Boot? DiscordBot => DiscordBotClient;
public static async Task Initialize() public static async Task Initialize()
{ {

View File

@@ -9,7 +9,7 @@ namespace PluginManager.Database;
public class SqlDatabase public class SqlDatabase
{ {
private readonly SQLiteConnection Connection; private readonly SQLiteConnection _connection;
/// <summary> /// <summary>
/// Initialize a SQL connection by specifing its private path /// Initialize a SQL connection by specifing its private path
@@ -22,7 +22,7 @@ public class SqlDatabase
if (!File.Exists(fileName)) if (!File.Exists(fileName))
SQLiteConnection.CreateFile(fileName); SQLiteConnection.CreateFile(fileName);
var connectionString = $"URI=file:{fileName}"; var connectionString = $"URI=file:{fileName}";
Connection = new SQLiteConnection(connectionString); _connection = new SQLiteConnection(connectionString);
} }
@@ -32,7 +32,7 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public async Task Open() public async Task Open()
{ {
await Connection.OpenAsync(); await _connection.OpenAsync();
} }
/// <summary> /// <summary>
@@ -55,7 +55,7 @@ public class SqlDatabase
query += ")"; query += ")";
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
await command.ExecuteNonQueryAsync(); await command.ExecuteNonQueryAsync();
} }
@@ -79,7 +79,7 @@ public class SqlDatabase
query += ")"; query += ")";
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
@@ -94,7 +94,7 @@ public class SqlDatabase
{ {
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
await command.ExecuteNonQueryAsync(); await command.ExecuteNonQueryAsync();
} }
@@ -109,7 +109,7 @@ public class SqlDatabase
{ {
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
@@ -163,7 +163,7 @@ public class SqlDatabase
throw new Exception($"Table {tableName} does not exist"); throw new Exception($"Table {tableName} does not exist");
await ExecuteAsync( await ExecuteAsync(
$"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
} }
/// <summary> /// <summary>
@@ -224,7 +224,7 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public async void Stop() public async void Stop()
{ {
await Connection.CloseAsync(); await _connection.CloseAsync();
} }
/// <summary> /// <summary>
@@ -236,9 +236,9 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT") public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT")
{ {
var command = Connection.CreateCommand(); var command = _connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}"; command.CommandText = $"SELECT * FROM {tableName}";
var reader = await command.ExecuteReaderAsync(); var reader = await command.ExecuteReaderAsync();
var tableColumns = new List<string>(); var tableColumns = new List<string>();
for (var i = 0; i < reader.FieldCount; i++) for (var i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i)); tableColumns.Add(reader.GetName(i));
@@ -260,9 +260,9 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT") public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT")
{ {
var command = Connection.CreateCommand(); var command = _connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}"; command.CommandText = $"SELECT * FROM {tableName}";
var reader = command.ExecuteReader(); var reader = command.ExecuteReader();
var tableColumns = new List<string>(); var tableColumns = new List<string>();
for (var i = 0; i < reader.FieldCount; i++) for (var i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i)); tableColumns.Add(reader.GetName(i));
@@ -282,7 +282,7 @@ public class SqlDatabase
/// <returns>True if the table exists, false if not</returns> /// <returns>True if the table exists, false if not</returns>
public async Task<bool> TableExistsAsync(string tableName) public async Task<bool> TableExistsAsync(string tableName)
{ {
var cmd = Connection.CreateCommand(); var cmd = _connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = await cmd.ExecuteScalarAsync(); var result = await cmd.ExecuteScalarAsync();
@@ -298,7 +298,7 @@ public class SqlDatabase
/// <returns>True if the table exists, false if not</returns> /// <returns>True if the table exists, false if not</returns>
public bool TableExists(string tableName) public bool TableExists(string tableName)
{ {
var cmd = Connection.CreateCommand(); var cmd = _connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = cmd.ExecuteScalar(); var result = cmd.ExecuteScalar();
@@ -315,7 +315,7 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public async Task CreateTableAsync(string tableName, params string[] columns) public async Task CreateTableAsync(string tableName, params string[] columns)
{ {
var cmd = Connection.CreateCommand(); var cmd = _connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
await cmd.ExecuteNonQueryAsync(); await cmd.ExecuteNonQueryAsync();
} }
@@ -328,7 +328,7 @@ public class SqlDatabase
/// <returns></returns> /// <returns></returns>
public void CreateTable(string tableName, params string[] columns) public void CreateTable(string tableName, params string[] columns)
{ {
var cmd = Connection.CreateCommand(); var cmd = _connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
@@ -340,10 +340,10 @@ public class SqlDatabase
/// <returns>The number of rows that the query modified</returns> /// <returns>The number of rows that the query modified</returns>
public async Task<int> ExecuteAsync(string query) public async Task<int> ExecuteAsync(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
await Connection.OpenAsync(); await _connection.OpenAsync();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var answer = await command.ExecuteNonQueryAsync(); var answer = await command.ExecuteNonQueryAsync();
return answer; return answer;
} }
@@ -354,10 +354,10 @@ public class SqlDatabase
/// <returns>The number of rows that the query modified</returns> /// <returns>The number of rows that the query modified</returns>
public int Execute(string query) public int Execute(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
Connection.Open(); _connection.Open();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var r = command.ExecuteNonQuery(); var r = command.ExecuteNonQuery();
return r; return r;
} }
@@ -369,10 +369,10 @@ public class SqlDatabase
/// <returns>The result is a string that has all values separated by space character</returns> /// <returns>The result is a string that has all values separated by space character</returns>
public async Task<string?> ReadDataAsync(string query) public async Task<string?> ReadDataAsync(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
await Connection.OpenAsync(); await _connection.OpenAsync();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var reader = await command.ExecuteReaderAsync(); var reader = await command.ExecuteReaderAsync();
var values = new object[reader.FieldCount]; var values = new object[reader.FieldCount];
if (reader.Read()) if (reader.Read())
@@ -391,10 +391,10 @@ public class SqlDatabase
/// <returns>The result is a string that has all values separated by space character</returns> /// <returns>The result is a string that has all values separated by space character</returns>
public string? ReadData(string query) public string? ReadData(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
Connection.Open(); _connection.Open();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var reader = command.ExecuteReader(); var reader = command.ExecuteReader();
var values = new object[reader.FieldCount]; var values = new object[reader.FieldCount];
if (reader.Read()) if (reader.Read())
@@ -413,10 +413,10 @@ public class SqlDatabase
/// <returns>The first row as separated items</returns> /// <returns>The first row as separated items</returns>
public async Task<object[]?> ReadDataArrayAsync(string query) public async Task<object[]?> ReadDataArrayAsync(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
await Connection.OpenAsync(); await _connection.OpenAsync();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var reader = await command.ExecuteReaderAsync(); var reader = await command.ExecuteReaderAsync();
var values = new object[reader.FieldCount]; var values = new object[reader.FieldCount];
if (reader.Read()) if (reader.Read())
@@ -436,10 +436,10 @@ public class SqlDatabase
/// <returns>The first row as separated items</returns> /// <returns>The first row as separated items</returns>
public object[]? ReadDataArray(string query) public object[]? ReadDataArray(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
Connection.Open(); _connection.Open();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var reader = command.ExecuteReader(); var reader = command.ExecuteReader();
var values = new object[reader.FieldCount]; var values = new object[reader.FieldCount];
if (reader.Read()) if (reader.Read())
@@ -459,10 +459,10 @@ public class SqlDatabase
/// <returns>A list of string arrays representing the values that the query returns</returns> /// <returns>A list of string arrays representing the values that the query returns</returns>
public async Task<List<string[]>?> ReadAllRowsAsync(string query) public async Task<List<string[]>?> ReadAllRowsAsync(string query)
{ {
if (!Connection.State.HasFlag(ConnectionState.Open)) if (!_connection.State.HasFlag(ConnectionState.Open))
await Connection.OpenAsync(); await _connection.OpenAsync();
var command = new SQLiteCommand(query, Connection); var command = new SQLiteCommand(query, _connection);
var reader = await command.ExecuteReaderAsync(); var reader = await command.ExecuteReaderAsync();
if (!reader.HasRows) if (!reader.HasRows)
return null; return null;
@@ -479,4 +479,163 @@ public class SqlDatabase
return rows; return rows;
} }
/// <summary>
/// Create a parameter for a query
/// </summary>
/// <param name="name">The name of the parameter</param>
/// <param name="value">The value of the parameter</param>
/// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns>
private SQLiteParameter? CreateParameter(string name, object value)
{
var parameter = new SQLiteParameter(name);
parameter.Value = value;
if (value is string)
parameter.DbType = DbType.String;
else if (value is int)
parameter.DbType = DbType.Int32;
else if (value is long)
parameter.DbType = DbType.Int64;
else if (value is float)
parameter.DbType = DbType.Single;
else if (value is double)
parameter.DbType = DbType.Double;
else if (value is bool)
parameter.DbType = DbType.Boolean;
else if (value is DateTime)
parameter.DbType = DbType.DateTime;
else if (value is byte[])
parameter.DbType = DbType.Binary;
else if (value is Guid)
parameter.DbType = DbType.Guid;
else if (value is decimal)
parameter.DbType = DbType.Decimal;
else if (value is TimeSpan)
parameter.DbType = DbType.Time;
else if (value is DateTimeOffset)
parameter.DbType = DbType.DateTimeOffset;
else if (value is ushort)
parameter.DbType = DbType.UInt16;
else if (value is uint)
parameter.DbType = DbType.UInt32;
else if (value is ulong)
parameter.DbType = DbType.UInt64;
else if (value is sbyte)
parameter.DbType = DbType.SByte;
else if (value is short)
parameter.DbType = DbType.Int16;
else if (value is byte)
parameter.DbType = DbType.Byte;
else if (value is char)
parameter.DbType = DbType.StringFixedLength;
else if (value is char[])
parameter.DbType = DbType.StringFixedLength;
else
return null;
return parameter;
}
/// <summary>
/// Create a parameter for a query. The function automatically detects the type of the value.
/// </summary>
/// <param name="parameterValues">The parameter raw inputs. The Key is name and the Value is the value of the parameter</param>
/// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns>
private SQLiteParameter? CreateParameter(KeyValuePair<string, object> parameterValues) =>
CreateParameter(parameterValues.Key, parameterValues.Value);
/// <summary>
/// Execute a query with parameters
/// </summary>
/// <param name="query">The query to execute</param>
/// <param name="parameters">The parameters of the query</param>
/// <returns>The number of rows that the query modified in the database</returns>
public async Task<int> ExecuteNonQueryAsync(string query, params KeyValuePair<string, object>[] parameters)
{
if (!_connection.State.HasFlag(ConnectionState.Open))
await _connection.OpenAsync();
var command = new SQLiteCommand(query, _connection);
foreach (var parameter in parameters)
{
var p = CreateParameter(parameter);
if (p is not null)
command.Parameters.Add(p);
}
return await command.ExecuteNonQueryAsync();
}
/// <summary>
/// Execute a query with parameters that returns a specific type of object. The function will return the first row of the result transformed into the specified type.
/// </summary>
/// <param name="query">The query to execute</param>
/// <param name="convertor">The convertor function that will convert each row of the response into an object of <typeparamref name="T"/></param>
/// <param name="parameters">The parameters of the query</param>
/// <typeparam name="T">The return object type</typeparam>
/// <returns>An object of type T that represents the output of the convertor function based on the array of objects that the first row of the result has</returns>
public async Task<T?> ReadObjectOfTypeAsync<T> (string query, Func<object[], T> convertor, params KeyValuePair<string, object>[] parameters)
{
if (!_connection.State.HasFlag(ConnectionState.Open))
await _connection.OpenAsync();
var command = new SQLiteCommand(query, _connection);
foreach (var parameter in parameters)
{
var p = CreateParameter(parameter);
if (p is not null)
command.Parameters.Add(p);
}
var reader = await command.ExecuteReaderAsync();
var values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return convertor(values);
}
return default;
}
/// <summary>
/// Execute a query with parameters that returns a specific type of object. The function will return a list of objects of the specified type.
/// </summary>
/// <param name="query">The query to execute</param>
/// <param name="convertor">The convertor from object[] to T</param>
/// <param name="parameters">The parameters of the query</param>
/// <typeparam name="T">The expected object type</typeparam>
/// <returns>A list of objects of type T that represents each line of the output of the specified query, converted to T</returns>
public async Task<List<T>> ReadListOfTypeAsync<T>(string query, Func<object[], T> convertor,
params KeyValuePair<string, object>[] parameters)
{
if (!_connection.State.HasFlag(ConnectionState.Open))
await _connection.OpenAsync();
var command = new SQLiteCommand(query, _connection);
foreach (var parameter in parameters)
{
var p = CreateParameter(parameter);
if (p is not null)
command.Parameters.Add(p);
}
var reader = await command.ExecuteReaderAsync();
//
if (!reader.HasRows)
return null;
List<T> rows = new();
while (await reader.ReadAsync())
{
var values = new object[reader.FieldCount];
reader.GetValues(values);
rows.Add(convertor(values));
}
return rows;
}
} }

View File

@@ -21,13 +21,13 @@ internal class Loader
{ {
internal Loader(string path, string extension) internal Loader(string path, string extension)
{ {
this.path = path; this.Path = path;
this.extension = extension; this.Extension = extension;
} }
private string path { get; } private string Path { get; }
private string extension { get; } private string Extension { get; }
internal event FileLoadedEventHandler? FileLoaded; internal event FileLoadedEventHandler? FileLoaded;
@@ -40,13 +40,13 @@ internal class Loader
List<DBSlashCommand> slashCommands = new(); List<DBSlashCommand> slashCommands = new();
List<DBCommand> commands = new(); List<DBCommand> commands = new();
if (!Directory.Exists(path)) if (!Directory.Exists(Path))
{ {
Directory.CreateDirectory(path); Directory.CreateDirectory(Path);
return (null, null, null); return (null, null, null);
} }
var files = Directory.GetFiles(path, $"*.{extension}", SearchOption.AllDirectories); var files = Directory.GetFiles(Path, $"*.{Extension}", SearchOption.AllDirectories);
foreach (var file in files) foreach (var file in files)
{ {
try try