90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
package prices
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type PriceDb struct {
|
|
ID string `bson:"_id" json:"id"`
|
|
CoingeckoID string `bson:"coingeckoId" json:"coingeckoId"`
|
|
Price string `bson:"price" json:"price"`
|
|
Datetime time.Time `bson:"dateTime" json:"dateTime"`
|
|
UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"`
|
|
}
|
|
|
|
type PriceRepository struct {
|
|
db *mongo.Database
|
|
collection *mongo.Collection
|
|
logger *zap.Logger
|
|
}
|
|
|
|
var ErrPriceNotFound = fmt.Errorf("price not found")
|
|
|
|
// NewPriceRepository creates a new price repository.
|
|
func NewPriceRepository(db *mongo.Database, logger *zap.Logger) *PriceRepository {
|
|
return &PriceRepository{
|
|
db: db,
|
|
collection: db.Collection("prices"),
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Upsert upserts a price.
|
|
func (p *PriceRepository) Upsert(ctx context.Context, coingeckoID string, price decimal.Decimal, dateTime time.Time) error {
|
|
id := p.createID(coingeckoID, dateTime)
|
|
model := &PriceDb{
|
|
ID: id,
|
|
CoingeckoID: coingeckoID,
|
|
Price: price.Truncate(8).String(),
|
|
Datetime: dateTime,
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
update := bson.M{
|
|
"$set": model,
|
|
"$setOnInsert": indexedAt(time.Now()),
|
|
"$inc": bson.D{{Key: "revision", Value: 1}},
|
|
}
|
|
|
|
opts := options.Update().SetUpsert(true)
|
|
var err error
|
|
_, err = p.collection.UpdateByID(ctx, model.ID, update, opts)
|
|
return err
|
|
}
|
|
|
|
// Find finds a price.
|
|
func (p *PriceRepository) Find(ctx context.Context, coingeckoID string, dateTime time.Time) (*PriceDb, error) {
|
|
id := p.createID(coingeckoID, dateTime)
|
|
var price PriceDb
|
|
err := p.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&price)
|
|
if err != nil {
|
|
if err == mongo.ErrNoDocuments {
|
|
return nil, ErrPriceNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &price, err
|
|
}
|
|
|
|
func (p *PriceRepository) createID(coingeckoID string, dateTime time.Time) string {
|
|
return fmt.Sprintf("%s-%s", coingeckoID, dateTime.Format(time.RFC3339))
|
|
}
|
|
|
|
func indexedAt(t time.Time) IndexingTimestamps {
|
|
return IndexingTimestamps{
|
|
IndexedAt: t,
|
|
}
|
|
}
|
|
|
|
type IndexingTimestamps struct {
|
|
IndexedAt time.Time `bson:"indexedAt"`
|
|
}
|