using Backend.Interface; using Npgsql; using NpgsqlTypes; namespace Backend.DatabaseHandler { public sealed class PostgresAnnotationStore : IAnnotationStore { private readonly string _connectionString; public PostgresAnnotationStore(IConfiguration configuration) { _connectionString = configuration.GetConnectionString("MarketDataDb") ?? throw new InvalidOperationException("Missing connection string: MarketDataDb"); } public async Task GetAsync( string user, string symbol, CancellationToken cancellationToken = default) { await using var conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(cancellationToken); const string sql = """ SELECT annotations FROM chart_annotations WHERE username = @user AND symbol = @symbol; """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("user", user); cmd.Parameters.AddWithValue("symbol", symbol); var result = await cmd.ExecuteScalarAsync(cancellationToken); return result as string; } public async Task UpsertAsync( string user, string symbol, string annotationsJson, CancellationToken cancellationToken = default) { await using var conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(cancellationToken); const string sql = """ INSERT INTO chart_annotations (username, symbol, annotations) VALUES (@user, @symbol, @annotations) ON CONFLICT (username, symbol) DO UPDATE SET annotations = @annotations; """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("user", user); cmd.Parameters.AddWithValue("symbol", symbol); cmd.Parameters.Add(new NpgsqlParameter("annotations", NpgsqlDbType.Jsonb) { Value = annotationsJson }); await cmd.ExecuteNonQueryAsync(cancellationToken); } public async Task DeleteAsync( string user, string symbol, CancellationToken cancellationToken = default) { await using var conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(cancellationToken); const string sql = """ DELETE FROM chart_annotations WHERE username = @user AND symbol = @symbol; """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("user", user); cmd.Parameters.AddWithValue("symbol", symbol); await cmd.ExecuteNonQueryAsync(cancellationToken); } } }