Yimaru-BackEnd/internal/repository/currency.go

97 lines
2.7 KiB
Go

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(&currency); 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
}