aboutsummaryrefslogtreecommitdiff
path: root/model/node.go
diff options
context:
space:
mode:
Diffstat (limited to 'model/node.go')
-rw-r--r--model/node.go157
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