package repository import ( "context" "database/sql" "fmt" "Yimaru-Backend/internal/domain" ) type CurrencyRepository interface { GetExchangeRate(ctx context.Context, from, to domain.IntCurrency) (domain.IntCurrencyRate, error) StoreExchangeRate(ctx context.Context, rate domain.IntCurrencyRate) error GetSupportedCurrencies(ctx context.Context) ([]domain.IntCurrency, error) } type CurrencyPostgresRepository struct { store *Store } func NewCurrencyPostgresRepository(store *Store) *CurrencyPostgresRepository { return &CurrencyPostgresRepository{store: store} } func (r *CurrencyPostgresRepository) GetExchangeRate(ctx context.Context, from, to domain.IntCurrency) (domain.IntCurrencyRate, error) { const query = ` SELECT from_currency, to_currency, rate, precision, valid_until FROM exchange_rates WHERE from_currency = $1 AND to_currency = $2 AND valid_until > NOW() ORDER BY created_at DESC LIMIT 1` var rate domain.IntCurrencyRate err := r.store.conn.QueryRow(ctx, query, from, to).Scan( &rate.From, &rate.To, &rate.Rate, &rate.ValidUntil, ) if err != nil { if err == sql.ErrNoRows { return domain.IntCurrencyRate{}, fmt.Errorf("%w: no rate found for %s to %s", domain.ErrIntCurrencyConversion, from, to) } return domain.IntCurrencyRate{}, fmt.Errorf("failed to get exchange rate: %w", err) } return rate, nil } func (r *CurrencyPostgresRepository) StoreExchangeRate(ctx context.Context, rate domain.IntCurrencyRate) error { const query = ` INSERT INTO exchange_rates (from_currency, to_currency, rate, precision, valid_until) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (from_currency, to_currency) DO UPDATE SET rate = EXCLUDED.rate, precision = EXCLUDED.precision, valid_until = EXCLUDED.valid_until, created_at = NOW()` _, err := r.store.conn.Exec(ctx, query, rate.From, rate.To, rate.Rate, rate.ValidUntil) if err != nil { return fmt.Errorf("failed to store exchange rate: %w", err) } return nil } func (r *CurrencyPostgresRepository) GetSupportedCurrencies(ctx context.Context) ([]domain.IntCurrency, error) { const query = `SELECT DISTINCT currency FROM supported_currencies ORDER BY currency` var currencies []domain.IntCurrency rows, err := r.store.conn.Query(ctx, query) if err != nil { return nil, fmt.Errorf("failed to get supported currencies: %w", err) } defer rows.Close() for rows.Next() { var currency domain.IntCurrency if err := rows.Scan(¤cy); err != nil { return nil, fmt.Errorf("failed to scan currency: %w", err) } currencies = append(currencies, currency) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("row iteration error: %w", err) } return currencies, nil }