Badges / coveralls (push) Successful in 1m4s
Allow us to generate year over year reports without having to rerun everything from the beginning. Co-authored-by: Natercio Moniz <[email protected]>
89 lines
2.6 KiB
Go
89 lines
2.6 KiB
Go
package trading212
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/nmoniz/any2anexoj/internal"
|
|
"github.com/nmoniz/any2anexoj/internal/ofigi"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
// recordState is the on-disk representation of a trading212.Record.
|
|
// Nature is intentionally omitted because it is resolved lazily via the
|
|
// OpenFIGI client on demand.
|
|
type recordState struct {
|
|
Symbol string `json:"symbol"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Kind internal.Kind `json:"kind"`
|
|
Quantity decimal.Decimal `json:"quantity"`
|
|
Price decimal.Decimal `json:"price"`
|
|
Fees decimal.Decimal `json:"fees"`
|
|
Taxes decimal.Decimal `json:"taxes"`
|
|
}
|
|
|
|
// RecordSerializer encodes and decodes trading212.Record values for the
|
|
// internal persistence layer. On decode it re-wires the lazy natureGetter to
|
|
// the supplied OpenFIGI client so a restored Record resolves Nature() via a
|
|
// fresh API call when needed.
|
|
type RecordSerializer struct {
|
|
figi *ofigi.Client
|
|
}
|
|
|
|
// NewRecordSerializer returns a RecordSerializer that uses figi to resolve
|
|
// Record.Nature() on load.
|
|
func NewRecordSerializer(figi *ofigi.Client) *RecordSerializer {
|
|
return &RecordSerializer{figi: figi}
|
|
}
|
|
|
|
// MarshalRecord encodes the given internal.Record as JSON. It returns an
|
|
// error if the record is not a trading212.Record (or a *trading212.Record).
|
|
func (s *RecordSerializer) MarshalRecord(_ context.Context, r internal.Record) ([]byte, error) {
|
|
var rec Record
|
|
switch v := r.(type) {
|
|
case Record:
|
|
rec = v
|
|
case *Record:
|
|
if v == nil {
|
|
return nil, fmt.Errorf("trading212: cannot marshal nil *trading212.Record")
|
|
}
|
|
rec = *v
|
|
default:
|
|
return nil, fmt.Errorf("trading212: cannot marshal %T as trading212.Record", r)
|
|
}
|
|
|
|
state := recordState{
|
|
Symbol: rec.symbol,
|
|
Timestamp: rec.timestamp,
|
|
Kind: rec.kind,
|
|
Quantity: rec.quantity,
|
|
Price: rec.price,
|
|
Fees: rec.fees,
|
|
Taxes: rec.taxes,
|
|
}
|
|
|
|
return json.Marshal(state)
|
|
}
|
|
|
|
// UnmarshalRecord decodes a JSON-encoded trading212.Record and re-wires its
|
|
// natureGetter to the serializer's OpenFIGI client.
|
|
func (s *RecordSerializer) UnmarshalRecord(ctx context.Context, data []byte) (internal.Record, error) {
|
|
var state recordState
|
|
if err := json.Unmarshal(data, &state); err != nil {
|
|
return nil, fmt.Errorf("unmarshal trading212 record: %w", err)
|
|
}
|
|
|
|
return Record{
|
|
symbol: state.Symbol,
|
|
timestamp: state.Timestamp,
|
|
kind: state.Kind,
|
|
quantity: state.Quantity,
|
|
price: state.Price,
|
|
fees: state.Fees,
|
|
taxes: state.Taxes,
|
|
natureGetter: figiNatureGetter(ctx, s.figi, state.Symbol),
|
|
}, nil
|
|
}
|