diff options
Diffstat (limited to 'model/node.go')
-rw-r--r-- | model/node.go | 157 |
1 files changed, 21 insertions, 136 deletions
diff --git a/model/node.go b/model/node.go index 0aabfcc..20020f6 100644 --- a/model/node.go +++ b/model/node.go @@ -1,154 +1,39 @@ 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 +type Node interface { + Type() NodeType + MarshalJSON() ([]byte, error) } // 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) { +func NewNode(value any) Node { switch value := value.(type) { case string: - n.Type = StringNode - n.StringValue = value + return &StringNode{ + Value: value, + } case float64: - n.Type = NumberNode - n.NumberValue = value + return &NumberNode{ + Value: value, + } case int: - n.Type = NumberNode - n.NumberValue = float64(value) + return &NumberNode{ + Value: float64(value), + } case NodeObjectValue: - n.Type = ObjectNode - meta, hasMeta := value["@"] - if hasMeta { - n.Meta = meta.ObjectValue - delete(value, "@") + return &ObjectNode{ + Value: 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 &ArrayNode{ + Value: value, } - 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 bool: + return &BooleanNode{ + Value: value, } - case ArrayNode: - n.ArrayValue = append(n.ArrayValue, node.ArrayValue...) default: - return fmt.Errorf("merge not implemented for type %s", n.Type) + return NullNode{} } - 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 |