97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-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
|
|
}
|