fixes
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// cartItemAlias mirrors CartItem but has no custom (Un)MarshalJSON, so it is
|
||||
// used to (de)serialize the typed fields without recursing.
|
||||
type cartItemAlias CartItem
|
||||
|
||||
// knownItemKeys is the set of top-level JSON object keys owned by typed
|
||||
// CartItem fields. Any other key in an item object is dynamic and kept in
|
||||
// CartItem.Extra.
|
||||
var knownItemKeys = buildKnownItemKeys()
|
||||
|
||||
func buildKnownItemKeys() map[string]struct{} {
|
||||
keys := make(map[string]struct{})
|
||||
t := reflect.TypeOf(CartItem{})
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
name, _, _ := strings.Cut(t.Field(i).Tag.Get("json"), ",")
|
||||
if name == "" {
|
||||
name = t.Field(i).Name // untagged fields serialize under their Go name
|
||||
}
|
||||
if name == "-" {
|
||||
continue // e.g. Extra itself
|
||||
}
|
||||
keys[name] = struct{}{}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// MarshalJSON emits the typed fields and flattens Extra onto the same object.
|
||||
// Typed fields take precedence on key collisions.
|
||||
func (c CartItem) MarshalJSON() ([]byte, error) {
|
||||
core, err := json.Marshal(cartItemAlias(c))
|
||||
if err != nil || len(c.Extra) == 0 {
|
||||
return core, err
|
||||
}
|
||||
merged := make(map[string]json.RawMessage, len(c.Extra)+8)
|
||||
if err := json.Unmarshal(core, &merged); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range c.Extra {
|
||||
if _, taken := merged[k]; taken {
|
||||
continue
|
||||
}
|
||||
merged[k] = v
|
||||
}
|
||||
return json.Marshal(merged)
|
||||
}
|
||||
|
||||
// UnmarshalJSON reads the typed fields and collects every other key into Extra.
|
||||
func (c *CartItem) UnmarshalJSON(data []byte) error {
|
||||
var alias cartItemAlias
|
||||
if err := json.Unmarshal(data, &alias); err != nil {
|
||||
return err
|
||||
}
|
||||
*c = CartItem(alias)
|
||||
|
||||
all := make(map[string]json.RawMessage)
|
||||
if err := json.Unmarshal(data, &all); err != nil {
|
||||
return err
|
||||
}
|
||||
for k := range all {
|
||||
if _, known := knownItemKeys[k]; known {
|
||||
delete(all, k)
|
||||
}
|
||||
}
|
||||
if len(all) > 0 {
|
||||
c.Extra = all
|
||||
} else {
|
||||
c.Extra = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user