diff --git a/PluralKit.Core/Database/Database.cs b/PluralKit.Core/Database/Database.cs index 660aecae..8d3547eb 100644 --- a/PluralKit.Core/Database/Database.cs +++ b/PluralKit.Core/Database/Database.cs @@ -16,7 +16,7 @@ using SqlKata.Compilers; namespace PluralKit.Core; -internal class Database: IDatabase +internal partial class Database: IDatabase { private readonly CoreConfig _config; @@ -153,92 +153,4 @@ internal class Database: IDatabase public override T[] Parse(object value) => Array.ConvertAll((TInner[])value, v => _factory(v)); } - - public async Task Execute(Func func) - { - await using var conn = await Obtain(); - await func(conn); - } - - public async Task Execute(Func> func) - { - await using var conn = await Obtain(); - return await func(conn); - } - - public async IAsyncEnumerable Execute(Func> func) - { - await using var conn = await Obtain(); - - await foreach (var val in func(conn)) - yield return val; - } - - public async Task ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "") - { - var query = _compiler.Compile(q); - using var conn = await Obtain(); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); - } - - public async Task ExecuteQuery(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = "") - { - if (conn == null) - return await ExecuteQuery(q, extraSql, queryName); - - var query = _compiler.Compile(q); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); - } - - public async Task QueryFirst(Query q, string extraSql = "", [CallerMemberName] string queryName = "") - { - var query = _compiler.Compile(q); - using var conn = await Obtain(); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - return await conn.QueryFirstOrDefaultAsync(query.Sql + $" {extraSql}", query.NamedBindings); - } - - public async Task QueryFirst(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = "") - { - if (conn == null) - return await QueryFirst(q, extraSql, queryName); - - var query = _compiler.Compile(q); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - return await conn.QueryFirstOrDefaultAsync(query.Sql + $" {extraSql}", query.NamedBindings); - } - - public async Task> Query(Query q, [CallerMemberName] string queryName = "") - { - var query = _compiler.Compile(q); - using var conn = await Obtain(); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - return await conn.QueryAsync(query.Sql, query.NamedBindings); - } - - public async IAsyncEnumerable QueryStream(Query q, [CallerMemberName] string queryName = "") - { - var query = _compiler.Compile(q); - using var conn = await Obtain(); - using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) - await foreach (var val in conn.QueryStreamAsync(query.Sql, query.NamedBindings)) - yield return val; - } - - // the procedures (message_context and proxy_members, as of writing) have their own metrics tracking elsewhere - // still, including them here for consistency - - public async Task QuerySingleProcedure(string queryName, object param) - { - using var conn = await Obtain(); - return await conn.QueryFirstAsync(queryName, param, commandType: CommandType.StoredProcedure); - } - - public async Task> QueryProcedure(string queryName, object param) - { - using var conn = await Obtain(); - return await conn.QueryAsync(queryName, param, commandType: CommandType.StoredProcedure); - } } \ No newline at end of file diff --git a/PluralKit.Core/Database/DatabaseQueries.cs b/PluralKit.Core/Database/DatabaseQueries.cs new file mode 100644 index 00000000..4d0b7a03 --- /dev/null +++ b/PluralKit.Core/Database/DatabaseQueries.cs @@ -0,0 +1,103 @@ +using System.Data; +using System.Runtime.CompilerServices; + +using App.Metrics; + +using Dapper; + +using Npgsql; + +using SqlKata; + +namespace PluralKit.Core; + +internal partial class Database: IDatabase +{ + public async Task Execute(Func func) + { + await using var conn = await Obtain(); + await func(conn); + } + + public async Task Execute(Func> func) + { + await using var conn = await Obtain(); + return await func(conn); + } + + public async IAsyncEnumerable Execute(Func> func) + { + await using var conn = await Obtain(); + + await foreach (var val in func(conn)) + yield return val; + } + + public async Task ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "") + { + var query = _compiler.Compile(q); + using var conn = await Obtain(); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); + } + + public async Task ExecuteQuery(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = "") + { + if (conn == null) + return await ExecuteQuery(q, extraSql, queryName); + + var query = _compiler.Compile(q); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); + } + + public async Task QueryFirst(Query q, string extraSql = "", [CallerMemberName] string queryName = "") + { + var query = _compiler.Compile(q); + using var conn = await Obtain(); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.QueryFirstOrDefaultAsync(query.Sql + $" {extraSql}", query.NamedBindings); + } + + public async Task QueryFirst(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = "") + { + if (conn == null) + return await QueryFirst(q, extraSql, queryName); + + var query = _compiler.Compile(q); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.QueryFirstOrDefaultAsync(query.Sql + $" {extraSql}", query.NamedBindings); + } + + public async Task> Query(Query q, [CallerMemberName] string queryName = "") + { + var query = _compiler.Compile(q); + using var conn = await Obtain(); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.QueryAsync(query.Sql, query.NamedBindings); + } + + public async IAsyncEnumerable QueryStream(Query q, [CallerMemberName] string queryName = "") + { + var query = _compiler.Compile(q); + using var conn = await Obtain(); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + await foreach (var val in conn.QueryStreamAsync(query.Sql, query.NamedBindings)) + yield return val; + } + + // the procedures (message_context and proxy_members, as of writing) have their own metrics tracking elsewhere + // still, including them here for consistency + + public async Task QuerySingleProcedure(string queryName, object param) + { + using var conn = await Obtain(); + return await conn.QueryFirstAsync(queryName, param, commandType: CommandType.StoredProcedure); + } + + public async Task> QueryProcedure(string queryName, object param) + { + using var conn = await Obtain(); + return await conn.QueryAsync(queryName, param, commandType: CommandType.StoredProcedure); + } +} \ No newline at end of file