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 ¤cyStore{ 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) }