using System; using System.Collections.Generic; using System.Data; using System.Data.SQLite; using System.IO; using System.Threading.Tasks; namespace PluginManager.Database; public class SqlDatabase { private readonly SQLiteConnection Connection; /// /// Initialize a SQL connection by specifing its private path /// /// The path to the database (it is starting from ./Data/Resources/) public SqlDatabase(string fileName) { if (!fileName.StartsWith("./Data/Resources/")) fileName = Path.Combine("./Data/Resources", fileName); if (!File.Exists(fileName)) SQLiteConnection.CreateFile(fileName); var connectionString = $"URI=file:{fileName}"; Connection = new SQLiteConnection(connectionString); } /// /// Open the SQL Connection. To close use the Stop() method /// /// public async Task Open() { await Connection.OpenAsync(); } /// /// /// Insert into a specified table some values /// /// /// The table name /// The values to be inserted (in the correct order and number) /// public async Task InsertAsync(string tableName, params string[] values) { var query = $"INSERT INTO {tableName} VALUES ("; for (var i = 0; i < values.Length; i++) { query += $"'{values[i]}'"; if (i != values.Length - 1) query += ", "; } query += ")"; var command = new SQLiteCommand(query, Connection); await command.ExecuteNonQueryAsync(); } /// /// /// Insert into a specified table some values /// /// /// The table name /// The values to be inserted (in the correct order and number) /// public void Insert(string tableName, params string[] values) { var query = $"INSERT INTO {tableName} VALUES ("; for (var i = 0; i < values.Length; i++) { query += $"'{values[i]}'"; if (i != values.Length - 1) query += ", "; } query += ")"; var command = new SQLiteCommand(query, Connection); command.ExecuteNonQuery(); } /// /// Remove every row in a table that has a certain propery /// /// The table name /// The column name that the search is made by /// The value that is searched in the specified column /// public async Task RemoveKeyAsync(string tableName, string KeyName, string KeyValue) { var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; var command = new SQLiteCommand(query, Connection); await command.ExecuteNonQueryAsync(); } /// /// Remove every row in a table that has a certain propery /// /// The table name /// The column name that the search is made by /// The value that is searched in the specified column /// public void RemoveKey(string tableName, string KeyName, string KeyValue) { var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; var command = new SQLiteCommand(query, Connection); command.ExecuteNonQuery(); } /// /// Check if the key exists in the table /// /// The table name /// The column that the search is made by /// The value that is searched in the specified column /// public async Task KeyExistsAsync(string tableName, string keyName, string KeyValue) { var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'"; if (await ReadDataAsync(query) is not null) return true; return false; } /// /// Check if the key exists in the table /// /// The table name /// The column that the search is made by /// The value that is searched in the specified column /// public bool KeyExists(string tableName, string keyName, string KeyValue) { var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'"; if (ReadData(query) is not null) return true; return false; } /// /// Set value of a column in a table /// /// The table name /// The column that the search is made by /// The value that is searched in the column specified /// The column that has to be modified /// The new value that will replace the old value from the column specified public async Task SetValueAsync( string tableName, string keyName, string KeyValue, string ResultColumnName, string ResultColumnValue) { if (!await TableExistsAsync(tableName)) throw new Exception($"Table {tableName} does not exist"); await ExecuteAsync( $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); } /// /// Set value of a column in a table /// /// The table name /// The column that the search is made by /// The value that is searched in the column specified /// The column that has to be modified /// The new value that will replace the old value from the column specified public void SetValue( string tableName, string keyName, string KeyValue, string ResultColumnName, string ResultColumnValue) { if (!TableExists(tableName)) throw new Exception($"Table {tableName} does not exist"); Execute($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); } /// /// Get value from a column in a table /// /// The table name /// The column that the search is made by /// The value that is searched in the specified column /// The column that has the result /// A string that has the requested value (can be null if nothing found) public async Task GetValueAsync( string tableName, string keyName, string KeyValue, string ResultColumnName) { if (!await TableExistsAsync(tableName)) throw new Exception($"Table {tableName} does not exist"); return await ReadDataAsync($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'"); } /// /// Get value from a column in a table /// /// The table name /// The column that the search is made by /// The value that is searched in the specified column /// The column that has the result /// A string that has the requested value (can be null if nothing found) public string? GetValue(string tableName, string keyName, string KeyValue, string ResultColumnName) { if (!TableExists(tableName)) throw new Exception($"Table {tableName} does not exist"); return ReadData($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'"); } /// /// Stop the connection to the SQL Database /// /// public async void Stop() { await Connection.CloseAsync(); } /// /// Change the structure of a table by adding new columns /// /// The table name /// The columns to be added /// The type of the columns (TEXT, INTEGER, FLOAT, etc) /// public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT") { var command = Connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; var reader = await command.ExecuteReaderAsync(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); foreach (var column in columns) if (!tableColumns.Contains(column)) { command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}"; await command.ExecuteNonQueryAsync(); } } /// /// Change the structure of a table by adding new columns /// /// The table name /// The columns to be added /// The type of the columns (TEXT, INTEGER, FLOAT, etc) /// public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT") { var command = Connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; var reader = command.ExecuteReader(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); foreach (var column in columns) if (!tableColumns.Contains(column)) { command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}"; command.ExecuteNonQuery(); } } /// /// Check if a table exists /// /// The table name /// True if the table exists, false if not public async Task TableExistsAsync(string tableName) { var cmd = Connection.CreateCommand(); cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; var result = await cmd.ExecuteScalarAsync(); if (result == null) return false; return true; } /// /// Check if a table exists /// /// The table name /// True if the table exists, false if not public bool TableExists(string tableName) { var cmd = Connection.CreateCommand(); cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; var result = cmd.ExecuteScalar(); if (result == null) return false; return true; } /// /// Create a table /// /// The table name /// The columns of the table /// public async Task CreateTableAsync(string tableName, params string[] columns) { var cmd = Connection.CreateCommand(); cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; await cmd.ExecuteNonQueryAsync(); } /// /// Create a table /// /// The table name /// The columns of the table /// public void CreateTable(string tableName, params string[] columns) { var cmd = Connection.CreateCommand(); cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; cmd.ExecuteNonQuery(); } /// /// Execute a custom query /// /// The query /// The number of rows that the query modified public async Task ExecuteAsync(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) await Connection.OpenAsync(); var command = new SQLiteCommand(query, Connection); var answer = await command.ExecuteNonQueryAsync(); return answer; } /// /// Execute a custom query /// /// The query /// The number of rows that the query modified public int Execute(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) Connection.Open(); var command = new SQLiteCommand(query, Connection); var r = command.ExecuteNonQuery(); return r; } /// /// Read data from the result table and return the first row /// /// The query /// The result is a string that has all values separated by space character public async Task ReadDataAsync(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) await Connection.OpenAsync(); var command = new SQLiteCommand(query, Connection); var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) { reader.GetValues(values); return string.Join(" ", values); } return null; } /// /// Read data from the result table and return the first row /// /// The query /// The result is a string that has all values separated by space character public string? ReadData(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) Connection.Open(); var command = new SQLiteCommand(query, Connection); var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) { reader.GetValues(values); return string.Join(" ", values); } return null; } /// /// Read data from the result table and return the first row /// /// The query /// The first row as separated items public async Task ReadDataArrayAsync(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) await Connection.OpenAsync(); var command = new SQLiteCommand(query, Connection); var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) { reader.GetValues(values); return values; } return null; } /// /// Read data from the result table and return the first row /// /// The query /// The first row as separated items public object[]? ReadDataArray(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) Connection.Open(); var command = new SQLiteCommand(query, Connection); var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) { reader.GetValues(values); return values; } return null; } /// /// Read all rows from the result table and return them as a list of string arrays. The string arrays contain the /// values of each row /// /// The query /// A list of string arrays representing the values that the query returns public async Task?> ReadAllRowsAsync(string query) { if (!Connection.State.HasFlag(ConnectionState.Open)) await Connection.OpenAsync(); var command = new SQLiteCommand(query, Connection); var reader = await command.ExecuteReaderAsync(); if (!reader.HasRows) return null; List rows = new(); while (await reader.ReadAsync()) { var values = new string[reader.FieldCount]; reader.GetValues(values); rows.Add(values); } if (rows.Count == 0) return null; return rows; } }