json/model/node.go

155 lines
3.1 KiB
Go
Raw Normal View History

2022-11-16 05:11:19 +03:00
package model
import (
"bytes"
"fmt"
"strconv"
)
// Node of JSON tree
type Node struct {
Type NodeType
2022-11-21 03:45:23 +03:00
Meta NodeObjectValue
StringValue string
NumberValue float64
ObjectValue NodeObjectValue
ArrayValue NodeArrayValue
BooleanValue bool
2022-11-16 05:11:19 +03:00
}
// NewNode creates new node from value
func NewNode(value any) *Node {
n := new(Node)
n.SetValue(value)
return n
}
// Value returns value of node
func (n *Node) Value() any {
switch n.Type {
case StringNode:
2022-11-21 03:45:23 +03:00
return n.StringValue
2022-11-16 05:11:19 +03:00
case NumberNode:
2022-11-21 03:45:23 +03:00
return n.NumberValue
2022-11-16 05:11:19 +03:00
case ObjectNode:
2022-11-21 03:45:23 +03:00
return n.ObjectValue
2022-11-16 05:11:19 +03:00
case ArrayNode:
2022-11-21 03:45:23 +03:00
return n.ArrayValue
2022-11-16 05:11:19 +03:00
case BooleanNode:
2022-11-21 03:45:23 +03:00
return n.BooleanValue
2022-11-16 05:11:19 +03:00
default:
return nil
}
}
// SetValue to node
func (n *Node) SetValue(value any) {
switch value := value.(type) {
case string:
n.Type = StringNode
2022-11-21 03:45:23 +03:00
n.StringValue = value
2022-11-16 05:11:19 +03:00
case float64:
n.Type = NumberNode
2022-11-21 03:45:23 +03:00
n.NumberValue = value
2022-11-16 05:11:19 +03:00
case int:
n.Type = NumberNode
2022-11-21 03:45:23 +03:00
n.NumberValue = float64(value)
2022-11-16 05:11:19 +03:00
case NodeObjectValue:
n.Type = ObjectNode
2022-11-21 03:45:23 +03:00
meta, hasMeta := value["@"]
if hasMeta {
n.Meta = meta.ObjectValue
delete(value, "@")
}
n.ObjectValue = value
2022-11-16 05:11:19 +03:00
case NodeArrayValue:
n.Type = ArrayNode
2022-11-21 03:45:23 +03:00
n.ArrayValue = value
2022-11-16 05:11:19 +03:00
case bool:
n.Type = BooleanNode
2022-11-21 03:45:23 +03:00
n.BooleanValue = value
2022-11-16 05:11:19 +03:00
default:
n.Type = NullNode
}
}
// MarshalJSON to []byte
func (n *Node) MarshalJSON() ([]byte, error) {
switch n.Type {
case StringNode:
2022-11-21 03:45:23 +03:00
return []byte(`"` + n.StringValue + `"`), nil
2022-11-16 05:11:19 +03:00
case NumberNode:
2022-11-21 03:45:23 +03:00
return []byte(strconv.FormatFloat(n.NumberValue, 'g', -1, 64)), nil
2022-11-16 05:11:19 +03:00
case ObjectNode:
2022-11-21 03:45:23 +03:00
result := make([][]byte, 0, len(n.ObjectValue))
for k, v := range n.ObjectValue {
2022-11-16 05:11:19 +03:00
b, err := v.MarshalJSON()
if err != nil {
return nil, err
}
result = append(result, []byte(fmt.Sprintf("\"%s\": %s", k, b)))
}
return bytes.Join(
[][]byte{
[]byte("{"),
bytes.Join(result, []byte(", ")),
[]byte("}"),
}, []byte("")), nil
case ArrayNode:
2022-11-21 03:45:23 +03:00
result := make([][]byte, 0, len(n.ArrayValue))
for _, v := range n.ArrayValue {
2022-11-16 05:11:19 +03:00
b, err := v.MarshalJSON()
if err != nil {
return nil, err
}
result = append(result, b)
}
return bytes.Join(
[][]byte{
[]byte("["),
bytes.Join(result, []byte(", ")),
[]byte("]"),
}, []byte("")), nil
case BooleanNode:
2022-11-21 03:45:23 +03:00
if n.BooleanValue {
2022-11-16 05:11:19 +03:00
return []byte("true"), nil
}
return []byte("false"), nil
default:
return []byte("null"), nil
}
}
2022-11-16 21:35:48 +03:00
// Merge two object or array nodes
func (n *Node) Merge(node *Node) error {
if n.Type != node.Type {
return fmt.Errorf("can't merge nodes of different types")
}
switch n.Type {
case ObjectNode:
2022-11-21 03:45:23 +03:00
for k, v := range node.ObjectValue {
n.ObjectValue[k] = v
2022-11-16 21:35:48 +03:00
}
case ArrayNode:
2022-11-21 03:45:23 +03:00
n.ArrayValue = append(n.ArrayValue, node.ArrayValue...)
2022-11-16 21:35:48 +03:00
default:
return fmt.Errorf("merge not implemented for type %s", n.Type)
}
return nil
}
// Len returns length of object or array nodes
func (n *Node) Len() (int, error) {
switch n.Type {
case ObjectNode:
2022-11-21 03:45:23 +03:00
return len(n.ObjectValue), nil
2022-11-16 21:35:48 +03:00
case ArrayNode:
2022-11-21 03:45:23 +03:00
return len(n.ArrayValue), nil
2022-11-16 21:35:48 +03:00
default:
return 0, fmt.Errorf("merge not implemented for type %s", n.Type)
}
}
2022-11-17 19:46:17 +03:00
// Meta represents node metadata
type Meta map[string]any