Files
sendico/api/fx/storage/mongo/store/currency.go
2025-12-26 14:25:18 +01:00

114 lines
3.3 KiB
Go

package store
import (
"context"
"errors"
"github.com/tech/sendico/fx/storage"
"github.com/tech/sendico/fx/storage/model"
"github.com/tech/sendico/pkg/db/repository"
ri "github.com/tech/sendico/pkg/db/repository/index"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
)
type currencyStore struct {
logger mlogger.Logger
repo repository.Repository
}
func NewCurrency(logger mlogger.Logger, db *mongo.Database) (storage.CurrencyStore, error) {
repo := repository.CreateMongoRepository(db, model.CurrenciesCollection)
index := &ri.Definition{
Keys: []ri.Key{
{Field: "code", Sort: ri.Asc},
},
Unique: true,
}
if err := repo.CreateIndex(index); err != nil {
logger.Error("Failed to ensure currencies index", zap.Error(err))
return nil, err
}
childLogger := logger.Named(model.CurrenciesCollection)
childLogger.Debug("Currency store initialised", zap.String("collection", model.CurrenciesCollection))
return &currencyStore{
logger: childLogger,
repo: repo,
}, nil
}
func (c *currencyStore) Get(ctx context.Context, code string) (*model.Currency, error) {
if code == "" {
c.logger.Warn("Attempt to fetch currency with empty code")
return nil, merrors.InvalidArgument("currencyStore: empty code")
}
result := &model.Currency{}
if err := c.repo.FindOneByFilter(ctx, repository.Filter("code", code), result); err != nil {
if errors.Is(err, merrors.ErrNoData) {
c.logger.Debug("Currency not found", zap.String("code", code))
}
return nil, err
}
c.logger.Debug("Currency loaded", zap.String("code", code))
return result, nil
}
func (c *currencyStore) List(ctx context.Context, codes ...string) ([]*model.Currency, error) {
query := repository.Query()
if len(codes) > 0 {
values := make([]any, len(codes))
for i, code := range codes {
values[i] = code
}
query = query.In(repository.Field("code"), values...)
}
currencies := make([]*model.Currency, 0)
err := c.repo.FindManyByFilter(ctx, query, func(cur *mongo.Cursor) error {
doc := &model.Currency{}
if err := cur.Decode(doc); err != nil {
return err
}
currencies = append(currencies, doc)
return nil
})
if err != nil {
c.logger.Warn("Failed to list currencies", zap.Error(err))
return nil, err
}
c.logger.Debug("Listed currencies", zap.Int("count", len(currencies)))
return currencies, nil
}
func (c *currencyStore) Upsert(ctx context.Context, currency *model.Currency) error {
if currency == nil {
c.logger.Warn("Attempt to upsert nil currency")
return merrors.InvalidArgument("currencyStore: nil currency")
}
if currency.Code == "" {
c.logger.Warn("Attempt to upsert currency with empty code")
return merrors.InvalidArgument("currencyStore: empty code")
}
existing := &model.Currency{}
filter := repository.Filter("code", currency.Code)
if err := c.repo.FindOneByFilter(ctx, filter, existing); err != nil {
if errors.Is(err, merrors.ErrNoData) {
c.logger.Debug("Inserting new currency", zap.String("code", currency.Code))
return c.repo.Insert(ctx, currency, filter)
}
c.logger.Warn("Failed to fetch currency", zap.Error(err), zap.String("code", currency.Code))
return err
}
if existing.GetID() != nil {
currency.SetID(*existing.GetID())
}
c.logger.Debug("Updating currency", zap.String("code", currency.Code))
return c.repo.Update(ctx, currency)
}