mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
More work on figuring out the DB stuff and converting EF code to linqtodb where it's easy
This commit is contained in:
@@ -6,73 +6,13 @@ using NadekoBot.Services.Database;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
|
||||
public class DbService
|
||||
public abstract class DbService
|
||||
{
|
||||
private readonly IBotCredsProvider _creds;
|
||||
/// <summary>
|
||||
/// Call this to apply all migrations
|
||||
/// </summary>
|
||||
public abstract Task SetupAsync();
|
||||
|
||||
// these are props because creds can change at runtime
|
||||
private string DbType => _creds.GetCreds().Db.Type.ToLowerInvariant().Trim();
|
||||
private string ConnString => _creds.GetCreds().Db.ConnectionString;
|
||||
|
||||
public DbService(IBotCredsProvider creds)
|
||||
{
|
||||
LinqToDBForEFTools.Initialize();
|
||||
Configuration.Linq.DisableQueryCache = true;
|
||||
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
public async Task SetupAsync()
|
||||
{
|
||||
var dbType = DbType;
|
||||
var connString = ConnString;
|
||||
|
||||
await using var context = CreateRawDbContext(dbType, connString);
|
||||
|
||||
// make sure sqlite db is in wal journal mode
|
||||
if (context is SqliteContext)
|
||||
{
|
||||
await context.Database.ExecuteSqlRawAsync("PRAGMA journal_mode=WAL");
|
||||
}
|
||||
|
||||
await context.Database.MigrateAsync();
|
||||
}
|
||||
|
||||
private static NadekoContext CreateRawDbContext(string dbType, string connString)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case "postgresql":
|
||||
case "postgres":
|
||||
case "pgsql":
|
||||
return new PostgreSqlContext(connString);
|
||||
case "mysql":
|
||||
return new MysqlContext(connString);
|
||||
case "sqlite":
|
||||
return new SqliteContext(connString);
|
||||
default:
|
||||
throw new NotSupportedException($"The database provide type of '{dbType}' is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private NadekoContext GetDbContextInternal()
|
||||
{
|
||||
var dbType = DbType;
|
||||
var connString = ConnString;
|
||||
|
||||
var context = CreateRawDbContext(dbType, connString);
|
||||
if (context is SqliteContext)
|
||||
{
|
||||
var conn = context.Database.GetDbConnection();
|
||||
conn.Open();
|
||||
using var com = conn.CreateCommand();
|
||||
com.CommandText = "PRAGMA synchronous=OFF";
|
||||
com.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
public NadekoContext GetDbContext()
|
||||
=> GetDbContextInternal();
|
||||
public abstract DbContext CreateRawDbContext(string dbType, string connString);
|
||||
public abstract DbContext GetDbContext();
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Services.Currency;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
@@ -52,7 +54,8 @@ public sealed class CurrencyService : ICurrencyService, INService
|
||||
if (type == CurrencyType.Default)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.DiscordUser
|
||||
await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => userIds.Contains(x.UserId))
|
||||
.UpdateAsync(du => new()
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Services.Currency;
|
||||
@@ -19,11 +20,11 @@ public class DefaultWallet : IWallet
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var userId = UserId;
|
||||
return await ctx.DiscordUser
|
||||
.ToLinqToDBTable()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Select(x => x.CurrencyAmount)
|
||||
.FirstOrDefaultAsync();
|
||||
return await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Select(x => x.CurrencyAmount)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> Take(long amount, TxData? txData)
|
||||
@@ -34,12 +35,13 @@ public class DefaultWallet : IWallet
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var userId = UserId;
|
||||
var changed = await ctx.DiscordUser
|
||||
.Where(x => x.UserId == userId && x.CurrencyAmount >= amount)
|
||||
.UpdateAsync(x => new()
|
||||
{
|
||||
CurrencyAmount = x.CurrencyAmount - amount
|
||||
});
|
||||
var changed = await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => x.UserId == userId && x.CurrencyAmount >= amount)
|
||||
.UpdateAsync(x => new()
|
||||
{
|
||||
CurrencyAmount = x.CurrencyAmount - amount
|
||||
});
|
||||
|
||||
if (changed == 0)
|
||||
return false;
|
||||
@@ -70,25 +72,26 @@ public class DefaultWallet : IWallet
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var userId = UserId;
|
||||
|
||||
|
||||
await using (var tran = await ctx.Database.BeginTransactionAsync())
|
||||
{
|
||||
var changed = await ctx.DiscordUser
|
||||
.Where(x => x.UserId == userId)
|
||||
.UpdateAsync(x => new()
|
||||
{
|
||||
CurrencyAmount = x.CurrencyAmount + amount
|
||||
});
|
||||
var changed = await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.UpdateAsync(x => new()
|
||||
{
|
||||
CurrencyAmount = x.CurrencyAmount + amount
|
||||
});
|
||||
|
||||
if (changed == 0)
|
||||
{
|
||||
await ctx.DiscordUser
|
||||
.ToLinqToDBTable()
|
||||
.Value(x => x.UserId, userId)
|
||||
.Value(x => x.Username, "Unknown")
|
||||
.Value(x => x.Discriminator, "????")
|
||||
.Value(x => x.CurrencyAmount, amount)
|
||||
.InsertAsync();
|
||||
await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Value(x => x.UserId, userId)
|
||||
.Value(x => x.Username, "Unknown")
|
||||
.Value(x => x.Discriminator, "????")
|
||||
.Value(x => x.CurrencyAmount, amount)
|
||||
.InsertAsync();
|
||||
}
|
||||
|
||||
await tran.CommitAsync();
|
||||
|
@@ -1,7 +1,9 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services;
|
||||
@@ -73,38 +75,36 @@ public sealed class BlacklistService : IExecOnMessage
|
||||
public void Reload(bool publish = true)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var toPublish = uow.Blacklist.AsNoTracking().ToArray();
|
||||
var toPublish = uow.GetTable<BlacklistEntry>().ToArray();
|
||||
blacklist = toPublish;
|
||||
if (publish)
|
||||
_pubSub.Pub(_blPubKey, toPublish);
|
||||
}
|
||||
|
||||
public void Blacklist(BlacklistType type, ulong id)
|
||||
public async Task Blacklist(BlacklistType type, ulong id)
|
||||
{
|
||||
if (_creds.OwnerIds.Contains(id))
|
||||
return;
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var item = new BlacklistEntry
|
||||
{
|
||||
ItemId = id,
|
||||
Type = type
|
||||
};
|
||||
uow.Blacklist.Add(item);
|
||||
uow.SaveChanges();
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
await uow
|
||||
.GetTable<BlacklistEntry>()
|
||||
.InsertAsync(() => new()
|
||||
{
|
||||
ItemId = id,
|
||||
Type = type,
|
||||
});
|
||||
|
||||
Reload();
|
||||
}
|
||||
|
||||
public void UnBlacklist(BlacklistType type, ulong id)
|
||||
public async Task UnBlacklist(BlacklistType type, ulong id)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var toRemove = uow.Blacklist.FirstOrDefault(bi => bi.ItemId == id && bi.Type == type);
|
||||
|
||||
if (toRemove is not null)
|
||||
uow.Blacklist.Remove(toRemove);
|
||||
|
||||
uow.SaveChanges();
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.GetTable<BlacklistEntry>()
|
||||
.Where(bi => bi.ItemId == id && bi.Type == type)
|
||||
.DeleteAsync();
|
||||
|
||||
Reload();
|
||||
}
|
||||
@@ -113,16 +113,21 @@ public sealed class BlacklistService : IExecOnMessage
|
||||
{
|
||||
using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var bc = uow.Blacklist;
|
||||
//blacklist the users
|
||||
var bc = uow.Set<BlacklistEntry>();
|
||||
bc.AddRange(toBlacklist.Select(x => new BlacklistEntry
|
||||
{
|
||||
ItemId = x,
|
||||
Type = BlacklistType.User
|
||||
}));
|
||||
|
||||
//clear their currencies
|
||||
uow.DiscordUser.RemoveFromMany(toBlacklist);
|
||||
// todo check if blacklist works and removes currency
|
||||
uow.GetTable<DiscordUser>()
|
||||
.UpdateAsync(x => toBlacklist.Contains(x.UserId),
|
||||
_ => new()
|
||||
{
|
||||
CurrencyAmount = 0
|
||||
});
|
||||
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
|
@@ -18,10 +18,11 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
||||
_db = db;
|
||||
_services = services;
|
||||
using var uow = _db.GetDbContext();
|
||||
_overrides = uow.DiscordPermOverrides.AsNoTracking()
|
||||
.AsEnumerable()
|
||||
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
||||
.ToConcurrent();
|
||||
_overrides = uow.Set<DiscordPermOverride>()
|
||||
.AsNoTracking()
|
||||
.AsEnumerable()
|
||||
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
||||
.ToConcurrent();
|
||||
}
|
||||
|
||||
public bool TryGetOverrides(ulong guildId, string commandName, out Nadeko.Bot.Db.GuildPerm? perm)
|
||||
@@ -52,18 +53,18 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
await using var uow = _db.GetDbContext();
|
||||
var over = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
||||
.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
||||
|
||||
if (over is null)
|
||||
{
|
||||
uow.Set<DiscordPermOverride>()
|
||||
.Add(over = new()
|
||||
{
|
||||
Command = commandName,
|
||||
Perm = (Nadeko.Bot.Db.GuildPerm)perm,
|
||||
GuildId = guildId
|
||||
});
|
||||
.Add(over = new()
|
||||
{
|
||||
Command = commandName,
|
||||
Perm = (Nadeko.Bot.Db.GuildPerm)perm,
|
||||
GuildId = guildId
|
||||
});
|
||||
}
|
||||
else
|
||||
over.Perm = (Nadeko.Bot.Db.GuildPerm)perm;
|
||||
@@ -77,10 +78,10 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var overrides = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
|
||||
uow.RemoveRange(overrides);
|
||||
await uow.SaveChangesAsync();
|
||||
@@ -95,9 +96,9 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var over = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
||||
|
||||
if (over is null)
|
||||
return;
|
||||
@@ -112,10 +113,10 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command)
|
||||
|
Reference in New Issue
Block a user