mlblive/internal/statsapi/feed.go

155 lines
2.7 KiB
Go

package statsapi
import (
"encoding/json"
"errors"
"log"
"strconv"
"strings"
)
type FeedParams struct {
GamePk string
}
type FeedResponse map[string]any
type Play struct {
Result result
About about
AtBatIndex int
}
type result struct {
Event string
Description string
RBI int
AwayScore int
HomeScore int
}
type about struct {
AtBatIndex json.Number
IsTopInning bool
Inning json.Number
IsScoringPlay bool
CaptivatingIndex json.Number
}
func expand(arr []any, idx int) []any {
var all []any
if idx < len(arr) {
all = arr
} else {
all = make([]any, idx+1)
copy(all[:len(arr)], arr)
all[idx] = make(map[string]any)
}
return all
}
func setLeaf(obj any, key string, value any) error {
var err error
switch v := obj.(type) {
case map[string]any:
log.Println("Formerly", v[key])
v[key] = value
log.Println("Now", v[key])
case []any:
idx, err := strconv.Atoi(key)
if err != nil {
break
}
v = expand(v, idx)
log.Println("Formerly", v[idx])
v[idx] = value
log.Println("Now", v[idx])
default:
err = errors.New("couldn't determine type")
}
return err
}
func getLeaf(key string, obj any) (any, error) {
switch v := obj.(type) {
case map[string]any:
val, ok := v[key]
if !ok {
return nil, errors.New("invalid key")
}
return val, nil
case []any:
idx, err := strconv.Atoi(key)
if err != nil {
return nil, err
}
if idx < 0 || idx >= len(v) {
return nil, errors.New("invalid index")
}
return v[idx], nil
default:
return nil, errors.New("couldn't determine type")
}
}
func set(path string, obj any, value any) error {
elems := strings.Split(path, "/")
leaf := elems[len(elems)-1]
leafPath := strings.Join(elems[:len(elems)-1], "/")
parent, err := get(leafPath, obj)
if err != nil {
return err
}
err = setLeaf(parent, leaf, value)
return err
}
func get(path string, obj any) (any, error) {
var err error
first, rest, found := strings.Cut(path, "/")
log.Println(first, rest)
if !found {
return getLeaf(first, obj)
} else if first == "" {
return get(rest, obj)
}
switch v := obj.(type) {
case map[string]any:
val, ok := v[first]
if !ok {
return v, errors.New("invalid key")
}
return get(rest, val)
case []any:
idx, err := strconv.Atoi(first)
if err != nil {
break
}
if idx < 0 || idx >= len(v) {
return v, errors.New("invalid index")
}
return get(rest, v[idx])
default:
err = errors.New("couldn't determine type")
}
return obj, err
}
func (f *FeedResponse) Patch(instr *instruction) error {
// TODO: need to handle each type of instruction separately: add,
// replace, remove, copy, move
log.Println("updating", instr.Path)
err := set(instr.Path, map[string]any(*f), instr.Value)
return err
}