Skip to content

Commit

Permalink
Add SQLite
Browse files Browse the repository at this point in the history
  • Loading branch information
MSWS committed Sep 7, 2024
1 parent 8dbbd98 commit 3b34039
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 35 deletions.
47 changes: 30 additions & 17 deletions GangsImpl/AbstractDB/AbstractInstanceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace GenericDB;

public abstract class AbstractInstanceManager<TK>(string connectionString,
string table_prefix, bool testing = false) {
protected DbConnection Connection;
protected DbConnection Connection = null!;
abstract protected string PrimaryKey { get; }
private string primaryTypeString => GetDBType(typeof(TK));

Expand All @@ -19,34 +19,43 @@ public void ClearCache() { }
public async Task<(bool, TV?)> Get<TV>(TK key, string statId) {
await createTable<TV>(statId);
try {
var dynamic = new DynamicParameters();
dynamic.Add(PrimaryKey, key);
var result = await Connection.QuerySingleAsync<TV>(
$"SELECT {(typeof(TV).IsPrimitive ? statId : getFieldNames<TV>())} FROM {table_prefix}_{statId} WHERE {PrimaryKey} = @{PrimaryKey}",
new { GangId = key });
$"SELECT {(typeof(TV).IsPrimitive ? statId : GetFieldNames<TV>())} FROM {table_prefix}_{statId} WHERE {PrimaryKey} = @{PrimaryKey}",
dynamic);
return (true, result);
} catch (InvalidOperationException) { return (false, default); }
} catch (InvalidOperationException e) {
if (!e.Message.Contains("Sequence contains no elements")) throw;
return (false, default);
}
}

public async Task<bool> Set<TV>(TK key, string statId, TV value) {
await createTable<TV>(statId);
var fields = typeof(TV)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList();

var columns = getFieldNames<TV>();
var values = getFieldNames<TV>("@");
virtual protected string GenerateInsertQuery<TV>(string statId,
IList<PropertyInfo> properties) {
var columns = GetFieldNames<TV>();
var values = GetFieldNames<TV>("@");

if (typeof(TV).IsPrimitive) {
columns = statId;
values = $"@{statId}";
}

var onDuplicate = string.Join(", ",
fields.Select(f => $"{f.Name} = @{f.Name}"));
properties.Select(f => $"{f.Name} = @{f.Name}"));
if (typeof(TV).IsPrimitive) onDuplicate = $"{statId} = @{statId}";
var cmd =
return
$"INSERT INTO {table_prefix}_{statId} ({PrimaryKey}, {columns}) VALUES (@{PrimaryKey}, {values}) ON DUPLICATE KEY UPDATE {onDuplicate}";
}

Debug.WriteLine(cmd);
public async Task<bool> Set<TV>(TK key, string statId, TV value) {
await createTable<TV>(statId);

var fields = typeof(TV)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList();

var cmd = GenerateInsertQuery<TV>(statId, fields);

var fieldValues = new DynamicParameters();
fieldValues.Add("@" + PrimaryKey, key);
Expand All @@ -70,7 +79,11 @@ await Connection.ExecuteAsync(
$"DELETE FROM {table_prefix}_{statId} WHERE {PrimaryKey} = @{PrimaryKey}",
dynamicParameters);
return true;
} catch (DbException) { return false; }
} catch (DbException e) {
if (e.Message.Contains("no such table")) return false;
if (e.Message.EndsWith("doesn't exist")) return false;
throw;
}
}

public void Start(BasePlugin? plugin, bool hotReload) {
Expand Down Expand Up @@ -130,7 +143,7 @@ private async Task createTable<TV>(string id) {
await Connection.ExecuteAsync(cmd);
}

private string getFieldNames<TV>(string prefix = "") {
protected string GetFieldNames<TV>(string prefix = "") {
var fields = typeof(TV)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,27 @@ namespace SQLImpl;
public class SQLGangInstanceManager(string connectionString,
string table_prefix, bool testing = false)
: AbstractInstanceManager<int>(connectionString, table_prefix, testing),
IPluginBehavior, IGangStatManager {
IGangStatManager {
override protected string PrimaryKey => "GangId";

public Task<(bool, TV?)> GetForGang<TV>(int key, string statId) {
return Get<TV>(key, statId);
}
public Task<(bool, TV?)> GetForGang<TV>(int key, string statId)
=> Get<TV>(key, statId);

public Task<bool> SetForGang<TV>(int gangId, string statId, TV value) {
return Set(gangId, statId, value);
}
public Task<bool> SetForGang<TV>(int gangId, string statId, TV value)
=> Set(gangId, statId, value);

public Task<bool> RemoveFromGang(int gangId, string statId) {
return Remove(gangId, statId);
}
public Task<bool> RemoveFromGang(int gangId, string statId)
=> Remove(gangId, statId);

override protected DbConnection CreateDbConnection(string connectionString) {
return new MySqlConnection(connectionString);
}
override protected DbConnection CreateDbConnection(string connectionString)
=> new MySqlConnection(connectionString);
}

public class SQLPlayerInstanceManager(string connectionString,
string table_prefix, bool testing = false)
: AbstractInstanceManager<ulong>(connectionString, table_prefix, testing),
IPlayerStatManager {
override protected string PrimaryKey => "GangId";
override protected string PrimaryKey => "Steam";

public Task<(bool, TV?)> GetForPlayer<TV>(ulong steam, string statId) {
return Get<TV>(steam, statId);
Expand All @@ -49,7 +45,6 @@ public Task<bool> RemoveFromPlayer(ulong steam, string statId) {
return Remove(steam, statId);
}

override protected DbConnection CreateDbConnection(string connectionString) {
return new MySqlConnection(connectionString);
}
override protected DbConnection CreateDbConnection(string connectionString)
=> new MySqlConnection(connectionString);
}
45 changes: 45 additions & 0 deletions GangsImpl/SQLite/SQLiteInstanceManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Data.Common;
using System.Reflection;
using GangsAPI.Services.Gang;
using GenericDB;
using Microsoft.Data.Sqlite;

namespace SQLite;

public class SQLiteGangInstanceManager(string connectionString,
string tablePrefix, bool testing = false)
: AbstractInstanceManager<int>(connectionString, tablePrefix, testing),
IGangStatManager {
private readonly string myTablePrefix = tablePrefix;
override protected string PrimaryKey => "GangId";

override protected DbConnection CreateDbConnection(string connectionString) {
return new SqliteConnection(connectionString);
}

override protected string GenerateInsertQuery<TV>(string statId,
IList<PropertyInfo> properties) {
var columns = GetFieldNames<TV>();
var values = GetFieldNames<TV>("@");

if (typeof(TV).IsPrimitive) {
columns = statId;
values = $"@{statId}";
}

var onDuplicate = string.Join(", ",
properties.Select(f => $"{f.Name} = @{f.Name}"));
if (typeof(TV).IsPrimitive) onDuplicate = $"{statId} = @{statId}";
return
$"INSERT INTO {myTablePrefix}_{statId} ({PrimaryKey}, {columns}) VALUES (@{PrimaryKey}, {values}) ON CONFLICT({PrimaryKey}) DO UPDATE SET {onDuplicate}";
}

public Task<(bool, TV?)> GetForGang<TV>(int key, string statId)
=> Get<TV>(key, statId);

public Task<bool> SetForGang<TV>(int gangId, string statId, TV value)
=> Set(gangId, statId, value);

public Task<bool> RemoveFromGang(int gangId, string statId)
=> Remove(gangId, statId);
}
5 changes: 4 additions & 1 deletion GangsTest/API/Services/Stat/Instance/Gang/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using GangsAPI.Services.Gang;
using Mock;
using SQLImpl;
using SQLite;

namespace GangsTest.API.Services.Stat.Instance.Gang;

Expand All @@ -10,7 +11,9 @@ public class TestData : IEnumerable<object[]> {
new MockInstanceStatManager(),
new SQLGangInstanceManager(
Environment.GetEnvironmentVariable("DB_GANGS_CONNECTION")
?? "Host=localhost;User=root;Database=gangs", "gang_inst_stats", true)
?? "Host=localhost;User=root;Database=gangs", "gang_inst_stats", true),
new SQLiteGangInstanceManager("Data Source=:memory:", "gang_inst_stats",
true)
];

public TestData() {
Expand Down
1 change: 1 addition & 0 deletions GangsTest/API/Services/Stat/Instance/TestParent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public bool Equals(IStat<int>? other) {

protected class Reputation(int Positive, int negative)
: IEquatable<Reputation> {
public Reputation() : this(0, 0) { }
public int Positive { get; } = Positive;
public int Negative { get; } = negative;

Expand Down

0 comments on commit 3b34039

Please sign in to comment.