Allow us to generate year over year reports without having to rerun everything from the beginning. Co-authored-by: Natercio Moniz <[email protected]>
This commit was merged in pull request #27.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user