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;
|
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
|
public abstract DbContext CreateRawDbContext(string dbType, string connString);
|
||||||
private string DbType => _creds.GetCreds().Db.Type.ToLowerInvariant().Trim();
|
public abstract DbContext GetDbContext();
|
||||||
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();
|
|
||||||
}
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
using NadekoBot.Services.Currency;
|
using NadekoBot.Services.Currency;
|
||||||
|
|
||||||
namespace NadekoBot.Services;
|
namespace NadekoBot.Services;
|
||||||
@@ -52,7 +54,8 @@ public sealed class CurrencyService : ICurrencyService, INService
|
|||||||
if (type == CurrencyType.Default)
|
if (type == CurrencyType.Default)
|
||||||
{
|
{
|
||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
await ctx.DiscordUser
|
await ctx
|
||||||
|
.GetTable<DiscordUser>()
|
||||||
.Where(x => userIds.Contains(x.UserId))
|
.Where(x => userIds.Contains(x.UserId))
|
||||||
.UpdateAsync(du => new()
|
.UpdateAsync(du => new()
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Currency;
|
namespace NadekoBot.Services.Currency;
|
||||||
@@ -19,11 +20,11 @@ public class DefaultWallet : IWallet
|
|||||||
{
|
{
|
||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
var userId = UserId;
|
var userId = UserId;
|
||||||
return await ctx.DiscordUser
|
return await ctx
|
||||||
.ToLinqToDBTable()
|
.GetTable<DiscordUser>()
|
||||||
.Where(x => x.UserId == userId)
|
.Where(x => x.UserId == userId)
|
||||||
.Select(x => x.CurrencyAmount)
|
.Select(x => x.CurrencyAmount)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Take(long amount, TxData? txData)
|
public async Task<bool> Take(long amount, TxData? txData)
|
||||||
@@ -34,12 +35,13 @@ public class DefaultWallet : IWallet
|
|||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
var userId = UserId;
|
var userId = UserId;
|
||||||
var changed = await ctx.DiscordUser
|
var changed = await ctx
|
||||||
.Where(x => x.UserId == userId && x.CurrencyAmount >= amount)
|
.GetTable<DiscordUser>()
|
||||||
.UpdateAsync(x => new()
|
.Where(x => x.UserId == userId && x.CurrencyAmount >= amount)
|
||||||
{
|
.UpdateAsync(x => new()
|
||||||
CurrencyAmount = x.CurrencyAmount - amount
|
{
|
||||||
});
|
CurrencyAmount = x.CurrencyAmount - amount
|
||||||
|
});
|
||||||
|
|
||||||
if (changed == 0)
|
if (changed == 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -70,25 +72,26 @@ public class DefaultWallet : IWallet
|
|||||||
|
|
||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
var userId = UserId;
|
var userId = UserId;
|
||||||
|
|
||||||
await using (var tran = await ctx.Database.BeginTransactionAsync())
|
await using (var tran = await ctx.Database.BeginTransactionAsync())
|
||||||
{
|
{
|
||||||
var changed = await ctx.DiscordUser
|
var changed = await ctx
|
||||||
.Where(x => x.UserId == userId)
|
.GetTable<DiscordUser>()
|
||||||
.UpdateAsync(x => new()
|
.Where(x => x.UserId == userId)
|
||||||
{
|
.UpdateAsync(x => new()
|
||||||
CurrencyAmount = x.CurrencyAmount + amount
|
{
|
||||||
});
|
CurrencyAmount = x.CurrencyAmount + amount
|
||||||
|
});
|
||||||
|
|
||||||
if (changed == 0)
|
if (changed == 0)
|
||||||
{
|
{
|
||||||
await ctx.DiscordUser
|
await ctx
|
||||||
.ToLinqToDBTable()
|
.GetTable<DiscordUser>()
|
||||||
.Value(x => x.UserId, userId)
|
.Value(x => x.UserId, userId)
|
||||||
.Value(x => x.Username, "Unknown")
|
.Value(x => x.Username, "Unknown")
|
||||||
.Value(x => x.Discriminator, "????")
|
.Value(x => x.Discriminator, "????")
|
||||||
.Value(x => x.CurrencyAmount, amount)
|
.Value(x => x.CurrencyAmount, amount)
|
||||||
.InsertAsync();
|
.InsertAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await tran.CommitAsync();
|
await tran.CommitAsync();
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using Microsoft.EntityFrameworkCore;
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Permissions.Services;
|
namespace NadekoBot.Modules.Permissions.Services;
|
||||||
@@ -73,38 +75,36 @@ public sealed class BlacklistService : IExecOnMessage
|
|||||||
public void Reload(bool publish = true)
|
public void Reload(bool publish = true)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var toPublish = uow.Blacklist.AsNoTracking().ToArray();
|
var toPublish = uow.GetTable<BlacklistEntry>().ToArray();
|
||||||
blacklist = toPublish;
|
blacklist = toPublish;
|
||||||
if (publish)
|
if (publish)
|
||||||
_pubSub.Pub(_blPubKey, toPublish);
|
_pubSub.Pub(_blPubKey, toPublish);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Blacklist(BlacklistType type, ulong id)
|
public async Task Blacklist(BlacklistType type, ulong id)
|
||||||
{
|
{
|
||||||
if (_creds.OwnerIds.Contains(id))
|
if (_creds.OwnerIds.Contains(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var item = new BlacklistEntry
|
|
||||||
{
|
await uow
|
||||||
ItemId = id,
|
.GetTable<BlacklistEntry>()
|
||||||
Type = type
|
.InsertAsync(() => new()
|
||||||
};
|
{
|
||||||
uow.Blacklist.Add(item);
|
ItemId = id,
|
||||||
uow.SaveChanges();
|
Type = type,
|
||||||
|
});
|
||||||
|
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnBlacklist(BlacklistType type, ulong id)
|
public async Task UnBlacklist(BlacklistType type, ulong id)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var toRemove = uow.Blacklist.FirstOrDefault(bi => bi.ItemId == id && bi.Type == type);
|
await uow.GetTable<BlacklistEntry>()
|
||||||
|
.Where(bi => bi.ItemId == id && bi.Type == type)
|
||||||
if (toRemove is not null)
|
.DeleteAsync();
|
||||||
uow.Blacklist.Remove(toRemove);
|
|
||||||
|
|
||||||
uow.SaveChanges();
|
|
||||||
|
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
@@ -113,16 +113,21 @@ public sealed class BlacklistService : IExecOnMessage
|
|||||||
{
|
{
|
||||||
using (var uow = _db.GetDbContext())
|
using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var bc = uow.Blacklist;
|
var bc = uow.Set<BlacklistEntry>();
|
||||||
//blacklist the users
|
|
||||||
bc.AddRange(toBlacklist.Select(x => new BlacklistEntry
|
bc.AddRange(toBlacklist.Select(x => new BlacklistEntry
|
||||||
{
|
{
|
||||||
ItemId = x,
|
ItemId = x,
|
||||||
Type = BlacklistType.User
|
Type = BlacklistType.User
|
||||||
}));
|
}));
|
||||||
|
|
||||||
//clear their currencies
|
// todo check if blacklist works and removes currency
|
||||||
uow.DiscordUser.RemoveFromMany(toBlacklist);
|
uow.GetTable<DiscordUser>()
|
||||||
|
.UpdateAsync(x => toBlacklist.Contains(x.UserId),
|
||||||
|
_ => new()
|
||||||
|
{
|
||||||
|
CurrencyAmount = 0
|
||||||
|
});
|
||||||
|
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,10 +18,11 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
|||||||
_db = db;
|
_db = db;
|
||||||
_services = services;
|
_services = services;
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
_overrides = uow.DiscordPermOverrides.AsNoTracking()
|
_overrides = uow.Set<DiscordPermOverride>()
|
||||||
.AsEnumerable()
|
.AsNoTracking()
|
||||||
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
.AsEnumerable()
|
||||||
.ToConcurrent();
|
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
||||||
|
.ToConcurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetOverrides(ulong guildId, string commandName, out Nadeko.Bot.Db.GuildPerm? perm)
|
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();
|
commandName = commandName.ToLowerInvariant();
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var over = await uow.Set<DiscordPermOverride>()
|
var over = await uow.Set<DiscordPermOverride>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
||||||
|
|
||||||
if (over is null)
|
if (over is null)
|
||||||
{
|
{
|
||||||
uow.Set<DiscordPermOverride>()
|
uow.Set<DiscordPermOverride>()
|
||||||
.Add(over = new()
|
.Add(over = new()
|
||||||
{
|
{
|
||||||
Command = commandName,
|
Command = commandName,
|
||||||
Perm = (Nadeko.Bot.Db.GuildPerm)perm,
|
Perm = (Nadeko.Bot.Db.GuildPerm)perm,
|
||||||
GuildId = guildId
|
GuildId = guildId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
over.Perm = (Nadeko.Bot.Db.GuildPerm)perm;
|
over.Perm = (Nadeko.Bot.Db.GuildPerm)perm;
|
||||||
@@ -77,10 +78,10 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
|||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var overrides = await uow.Set<DiscordPermOverride>()
|
var overrides = await uow.Set<DiscordPermOverride>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(x => x.GuildId == guildId)
|
.Where(x => x.GuildId == guildId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
uow.RemoveRange(overrides);
|
uow.RemoveRange(overrides);
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
@@ -95,9 +96,9 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
|||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var over = await uow.Set<DiscordPermOverride>()
|
var over = await uow.Set<DiscordPermOverride>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
||||||
|
|
||||||
if (over is null)
|
if (over is null)
|
||||||
return;
|
return;
|
||||||
@@ -112,10 +113,10 @@ public class DiscordPermOverrideService : INService, IExecPreCommand, IDiscordPe
|
|||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
return await uow.Set<DiscordPermOverride>()
|
return await uow.Set<DiscordPermOverride>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(x => x.GuildId == guildId)
|
.Where(x => x.GuildId == guildId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command)
|
public async Task<bool> ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command)
|
||||||
|
@@ -42,7 +42,7 @@ public static class DiscordUserExtensions
|
|||||||
});
|
});
|
||||||
|
|
||||||
public static Task EnsureUserCreatedAsync(
|
public static Task EnsureUserCreatedAsync(
|
||||||
this NadekoBaseContext ctx,
|
this DbContext ctx,
|
||||||
ulong userId)
|
ulong userId)
|
||||||
=> ctx.GetTable<DiscordUser>()
|
=> ctx.GetTable<DiscordUser>()
|
||||||
.InsertOrUpdateAsync(
|
.InsertOrUpdateAsync(
|
||||||
@@ -66,7 +66,7 @@ public static class DiscordUserExtensions
|
|||||||
|
|
||||||
//temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown
|
//temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown
|
||||||
public static DiscordUser GetOrCreateUser(
|
public static DiscordUser GetOrCreateUser(
|
||||||
this NadekoBaseContext ctx,
|
this DbContext ctx,
|
||||||
ulong userId,
|
ulong userId,
|
||||||
string username,
|
string username,
|
||||||
string discrim,
|
string discrim,
|
||||||
|
@@ -65,7 +65,7 @@ public static class GuildConfigExtensions
|
|||||||
/// <param name="includes">Use to manipulate the set however you want. Pass null to include everything</param>
|
/// <param name="includes">Use to manipulate the set however you want. Pass null to include everything</param>
|
||||||
/// <returns>Config for the guild</returns>
|
/// <returns>Config for the guild</returns>
|
||||||
public static GuildConfig GuildConfigsForId(
|
public static GuildConfig GuildConfigsForId(
|
||||||
this NadekoBaseContext ctx,
|
this DbContext ctx,
|
||||||
ulong guildId,
|
ulong guildId,
|
||||||
Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes)
|
Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes)
|
||||||
{
|
{
|
||||||
@@ -193,7 +193,7 @@ public static class GuildConfigExtensions
|
|||||||
conf.CleverbotEnabled = cleverbotEnabled;
|
conf.CleverbotEnabled = cleverbotEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XpSettings XpSettingsFor(this NadekoBaseContext ctx, ulong guildId)
|
public static XpSettings XpSettingsFor(this DbContext ctx, ulong guildId)
|
||||||
{
|
{
|
||||||
var gc = ctx.GuildConfigsForId(guildId,
|
var gc = ctx.GuildConfigsForId(guildId,
|
||||||
set => set.Include(x => x.XpSettings)
|
set => set.Include(x => x.XpSettings)
|
||||||
|
@@ -9,9 +9,9 @@ namespace NadekoBot.Db;
|
|||||||
|
|
||||||
public static class UserXpExtensions
|
public static class UserXpExtensions
|
||||||
{
|
{
|
||||||
public static UserXpStats GetOrCreateUserXpStats(this NadekoContext ctx, ulong guildId, ulong userId)
|
public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId)
|
||||||
{
|
{
|
||||||
var usr = ctx.UserXpStats.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
|
var usr = ctx.Set<UserXpStats>().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
|
||||||
|
|
||||||
if (usr is null)
|
if (usr is null)
|
||||||
{
|
{
|
||||||
|
@@ -75,24 +75,24 @@ public static class WaifuExtensions
|
|||||||
.Select(x => x.Waifu.UserId)
|
.Select(x => x.Waifu.UserId)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
public static async Task<WaifuInfoStats> GetWaifuInfoAsync(this NadekoContext ctx, ulong userId)
|
public static async Task<WaifuInfoStats> GetWaifuInfoAsync(this DbContext ctx, ulong userId)
|
||||||
{
|
{
|
||||||
await ctx.WaifuInfo
|
await ctx.Set<WaifuInfo>()
|
||||||
.ToLinqToDBTable()
|
.ToLinqToDBTable()
|
||||||
.InsertOrUpdateAsync(() => new()
|
.InsertOrUpdateAsync(() => new()
|
||||||
{
|
{
|
||||||
AffinityId = null,
|
AffinityId = null,
|
||||||
ClaimerId = null,
|
ClaimerId = null,
|
||||||
Price = 1,
|
Price = 1,
|
||||||
WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First()
|
WaifuId = ctx.Set<DiscordUser>().Where(x => x.UserId == userId).Select(x => x.Id).First()
|
||||||
},
|
},
|
||||||
_ => new(),
|
_ => new(),
|
||||||
() => new()
|
() => new()
|
||||||
{
|
{
|
||||||
WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First()
|
WaifuId = ctx.Set<DiscordUser>().Where(x => x.UserId == userId).Select(x => x.Id).First()
|
||||||
});
|
});
|
||||||
|
|
||||||
var toReturn = ctx.WaifuInfo.AsQueryable()
|
var toReturn = ctx.Set<WaifuInfo>().AsQueryable()
|
||||||
.Where(w => w.WaifuId
|
.Where(w => w.WaifuId
|
||||||
== ctx.Set<DiscordUser>()
|
== ctx.Set<DiscordUser>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
@@ -120,7 +120,7 @@ public static class WaifuExtensions
|
|||||||
.Where(u => u.Id == w.AffinityId)
|
.Where(u => u.Id == w.AffinityId)
|
||||||
.Select(u => u.Username + "#" + u.Discriminator)
|
.Select(u => u.Username + "#" + u.Discriminator)
|
||||||
.FirstOrDefault(),
|
.FirstOrDefault(),
|
||||||
ClaimCount = ctx.WaifuInfo.AsQueryable().Count(x => x.ClaimerId == w.WaifuId),
|
ClaimCount = ctx.Set<WaifuInfo>().AsQueryable().Count(x => x.ClaimerId == w.WaifuId),
|
||||||
ClaimerName =
|
ClaimerName =
|
||||||
ctx.Set<DiscordUser>()
|
ctx.Set<DiscordUser>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace NadekoBot.Db;
|
|
||||||
|
|
||||||
public abstract class NadekoBaseContext : DbContext
|
|
||||||
{
|
|
||||||
}
|
|
@@ -12,9 +12,9 @@ public static class PollExtensions
|
|||||||
.Include(x => x.Votes)
|
.Include(x => x.Votes)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
public static void RemovePoll(this NadekoContext ctx, int id)
|
public static void RemovePoll(this DbContext ctx, int id)
|
||||||
{
|
{
|
||||||
var p = ctx.Poll.Include(x => x.Answers).Include(x => x.Votes).FirstOrDefault(x => x.Id == id);
|
var p = ctx.Set<Poll>().Include(x => x.Answers).Include(x => x.Votes).FirstOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
if (p is null)
|
if (p is null)
|
||||||
return;
|
return;
|
||||||
@@ -31,6 +31,6 @@ public static class PollExtensions
|
|||||||
p.Answers.Clear();
|
p.Answers.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Poll.Remove(p);
|
ctx.Set<Poll>().Remove(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -52,7 +52,7 @@ public class PollRunner
|
|||||||
finally { _locker.Release(); }
|
finally { _locker.Release(); }
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var trackedPoll = uow.Poll.FirstOrDefault(x => x.Id == Poll.Id);
|
var trackedPoll = uow.Set<Poll>().FirstOrDefault(x => x.Id == Poll.Id);
|
||||||
trackedPoll.Votes.Add(voteObj);
|
trackedPoll.Votes.Add(voteObj);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
return true;
|
return true;
|
||||||
|
@@ -24,15 +24,15 @@ public class PollService : IExecOnMessage
|
|||||||
_eb = eb;
|
_eb = eb;
|
||||||
|
|
||||||
using var uow = db.GetDbContext();
|
using var uow = db.GetDbContext();
|
||||||
ActivePolls = uow.Poll.GetAllPolls()
|
ActivePolls = uow.Set<Poll>().GetAllPolls()
|
||||||
.ToDictionary(x => x.GuildId,
|
.ToDictionary(x => x.GuildId,
|
||||||
x =>
|
x =>
|
||||||
{
|
{
|
||||||
var pr = new PollRunner(db, x);
|
var pr = new PollRunner(db, x);
|
||||||
pr.OnVoted += Pr_OnVoted;
|
pr.OnVoted += Pr_OnVoted;
|
||||||
return pr;
|
return pr;
|
||||||
})
|
})
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Poll CreatePoll(ulong guildId, ulong channelId, string input)
|
public Poll CreatePoll(ulong guildId, ulong channelId, string input)
|
||||||
@@ -44,10 +44,10 @@ public class PollService : IExecOnMessage
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var col = new IndexedCollection<PollAnswer>(data.Skip(1)
|
var col = new IndexedCollection<PollAnswer>(data.Skip(1)
|
||||||
.Select(x => new PollAnswer
|
.Select(x => new PollAnswer
|
||||||
{
|
{
|
||||||
Text = x
|
Text = x
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ public class PollService : IExecOnMessage
|
|||||||
{
|
{
|
||||||
using (var uow = _db.GetDbContext())
|
using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
uow.Poll.Add(p);
|
uow.Set<Poll>().Add(p);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +98,13 @@ public class PollService : IExecOnMessage
|
|||||||
var toDelete = await msg.Channel.SendConfirmAsync(_eb,
|
var toDelete = await msg.Channel.SendConfirmAsync(_eb,
|
||||||
_strs.GetText(strs.poll_voted(Format.Bold(usr.ToString())), usr.GuildId));
|
_strs.GetText(strs.poll_voted(Format.Bold(usr.ToString())), usr.GuildId));
|
||||||
toDelete.DeleteAfter(5);
|
toDelete.DeleteAfter(5);
|
||||||
try { await msg.DeleteAsync(); }
|
try
|
||||||
catch { }
|
{
|
||||||
|
await msg.DeleteAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ExecOnMessageAsync(IGuild guild, IUserMessage msg)
|
public async Task<bool> ExecOnMessageAsync(IGuild guild, IUserMessage msg)
|
||||||
|
@@ -124,9 +124,9 @@ public partial class Permissions
|
|||||||
private async Task Blacklist(AddRemove action, ulong id, BlacklistType type)
|
private async Task Blacklist(AddRemove action, ulong id, BlacklistType type)
|
||||||
{
|
{
|
||||||
if (action == AddRemove.Add)
|
if (action == AddRemove.Add)
|
||||||
_service.Blacklist(type, id);
|
await _service.Blacklist(type, id);
|
||||||
else
|
else
|
||||||
_service.UnBlacklist(type, id);
|
await _service.UnBlacklist(type, id);
|
||||||
|
|
||||||
if (action == AddRemove.Add)
|
if (action == AddRemove.Add)
|
||||||
{
|
{
|
||||||
|
@@ -24,4 +24,8 @@
|
|||||||
<ProjectReference Include="..\Nadeko.Bot.Generators.Cloneable\Nadeko.Bot.Generators.Cloneable.csproj" OutputItemType="Analyzer" />
|
<ProjectReference Include="..\Nadeko.Bot.Generators.Cloneable\Nadeko.Bot.Generators.Cloneable.csproj" OutputItemType="Analyzer" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="_Common\Db\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
76
src/NadekoBot/Db/NadekoDbService.cs
Normal file
76
src/NadekoBot/Db/NadekoDbService.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using LinqToDB.Common;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Database;
|
||||||
|
|
||||||
|
public sealed class NadekoDbService : DbService
|
||||||
|
{
|
||||||
|
private readonly IBotCredsProvider _creds;
|
||||||
|
|
||||||
|
// 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 NadekoDbService(IBotCredsProvider creds)
|
||||||
|
{
|
||||||
|
LinqToDBForEFTools.Initialize();
|
||||||
|
Configuration.Linq.DisableQueryCache = true;
|
||||||
|
|
||||||
|
_creds = creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override 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 override NadekoContext GetDbContext()
|
||||||
|
=> GetDbContextInternal();
|
||||||
|
}
|
Reference in New Issue
Block a user