using Backend.Interface; using Npgsql; namespace Backend.DatabaseHandler { public sealed class PostgresUserLocationStore : IUserLocationStore { private readonly string _connectionString; public PostgresUserLocationStore(IConfiguration configuration) { _connectionString = configuration.GetConnectionString("MarketDataDb") ?? throw new InvalidOperationException("Missing connection string: MarketDataDb"); } public async Task GetAsync( string user, CancellationToken cancellationToken = default) { await using var conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(cancellationToken); const string sql = """ SELECT username, city, latitude, longitude FROM user_location WHERE username = @user; """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("user", user.Trim()); await using var reader = await cmd.ExecuteReaderAsync(cancellationToken); if (!await reader.ReadAsync(cancellationToken)) return null; return new UserLocationRecord { Username = reader.GetString(0), City = reader.GetString(1), Latitude = reader.GetDouble(2), Longitude = reader.GetDouble(3) }; } public async Task UpsertAsync( UserLocationRecord record, CancellationToken cancellationToken = default) { await using var conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(cancellationToken); const string sql = """ INSERT INTO user_location (username, city, latitude, longitude) VALUES (@user, @city, @lat, @lng) ON CONFLICT (username) DO UPDATE SET city = @city, latitude = @lat, longitude = @lng; """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("user", record.Username); cmd.Parameters.AddWithValue("city", record.City); cmd.Parameters.AddWithValue("lat", record.Latitude); cmd.Parameters.AddWithValue("lng", record.Longitude); await cmd.ExecuteNonQueryAsync(cancellationToken); } } }