155 lines
3.1 KiB
Go
155 lines
3.1 KiB
Go
package model
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strconv"
|
|
)
|
|
|
|
// Node of JSON tree
|
|
type Node struct {
|
|
Type NodeType
|
|
Meta NodeObjectValue
|
|
StringValue string
|
|
NumberValue float64
|
|
ObjectValue NodeObjectValue
|
|
ArrayValue NodeArrayValue
|
|
BooleanValue bool
|
|
}
|
|
|
|
// 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:
|
|
return n.StringValue
|
|
case NumberNode:
|
|
return n.NumberValue
|
|
case ObjectNode:
|
|
return n.ObjectValue
|
|
case ArrayNode:
|
|
return n.ArrayValue
|
|
case BooleanNode:
|
|
return n.BooleanValue
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// SetValue to node
|
|
func (n *Node) SetValue(value any) {
|
|
switch value := value.(type) {
|
|
case string:
|
|
n.Type = StringNode
|
|
n.StringValue = value
|
|
case float64:
|
|
n.Type = NumberNode
|
|
n.NumberValue = value
|
|
case int:
|
|
n.Type = NumberNode
|
|
n.NumberValue = float64(value)
|
|
case NodeObjectValue:
|
|
n.Type = ObjectNode
|
|
meta, hasMeta := value["@"]
|
|
if hasMeta {
|
|
n.Meta = meta.ObjectValue
|
|
delete(value, "@")
|
|
}
|
|
n.ObjectValue = value
|
|
case NodeArrayValue:
|
|
n.Type = ArrayNode
|
|
n.ArrayValue = value
|
|
case bool:
|
|
n.Type = BooleanNode
|
|
n.BooleanValue = value
|
|
default:
|
|
n.Type = NullNode
|
|
}
|
|
}
|
|
|
|
// MarshalJSON to []byte
|
|
func (n *Node) MarshalJSON() ([]byte, error) {
|
|
switch n.Type {
|
|
case StringNode:
|
|
return []byte(`"` + n.StringValue + `"`), nil
|
|
case NumberNode:
|
|
return []byte(strconv.FormatFloat(n.NumberValue, 'g', -1, 64)), nil
|
|
case ObjectNode:
|
|
result := make([][]byte, 0, len(n.ObjectValue))
|
|
for k, v := range n.ObjectValue {
|
|
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:
|
|
result := make([][]byte, 0, len(n.ArrayValue))
|
|
for _, v := range n.ArrayValue {
|
|
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:
|
|
if n.BooleanValue {
|
|
return []byte("true"), nil
|
|
}
|
|
return []byte("false"), nil
|
|
default:
|
|
return []byte("null"), nil
|
|
}
|
|
}
|
|
|
|
// 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:
|
|
for k, v := range node.ObjectValue {
|
|
n.ObjectValue[k] = v
|
|
}
|
|
case ArrayNode:
|
|
n.ArrayValue = append(n.ArrayValue, node.ArrayValue...)
|
|
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:
|
|
return len(n.ObjectValue), nil
|
|
case ArrayNode:
|
|
return len(n.ArrayValue), nil
|
|
default:
|
|
return 0, fmt.Errorf("merge not implemented for type %s", n.Type)
|
|
}
|
|
}
|
|
|
|
// Meta represents node metadata
|
|
type Meta map[string]any
|