using System.Data; using System.Runtime.CompilerServices; using App.Metrics; using Dapper; 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); } }