File: gjp.go

package info (click to toggle)
golang-github-tideland-golib 4.24.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,144 kB
  • sloc: makefile: 4
file content (155 lines) | stat: -rw-r--r-- 3,538 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Tideland Go Library - Generic JSON Processor
//
// Copyright (C) 2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package gjp

//--------------------
// IMPORTS
//--------------------

import (
	"encoding/json"

	"github.com/tideland/golib/errors"
	"github.com/tideland/golib/stringex"
)

//--------------------
// DOCUMENT
//--------------------

// PathValue is the combination of path and value.
type PathValue struct {
	Path  string
	Value Value
}

// PathValues contains a number of path/value combinations.
type PathValues []PathValue

// ValueProcessor describes a function for the processing of
// values while iterating over a document.
type ValueProcessor func(path string, value Value) error

// Document represents one JSON document.
type Document interface {
	json.Marshaler

	// Length returns the number of elements for the given path.
	Length(path string) int

	// SetValueAt sets the value at the given path.
	SetValueAt(path string, value interface{}) error

	// ValueAt returns the addressed value.
	ValueAt(path string) Value

	// Clear removes the so far build document data.
	Clear()

	// Query allows to find pathes matching a given pattern.
	Query(pattern string) (PathValues, error)

	// Process iterates over a document and processes its values.
	// There's no order, so nesting into an embedded document or
	// list may come earlier than higher level paths.
	Process(processor ValueProcessor) error
}

// document implements Document.
type document struct {
	separator string
	root      interface{}
}

// Parse reads a raw document and returns it as
// accessible document.
func Parse(data []byte, separator string) (Document, error) {
	var root interface{}
	err := json.Unmarshal(data, &root)
	if err != nil {
		return nil, errors.Annotate(err, ErrUnmarshalling, errorMessages)
	}
	return &document{
		separator: separator,
		root:      root,
	}, nil
}

// NewDocument creates a new empty document.
func NewDocument(separator string) Document {
	return &document{
		separator: separator,
	}
}

// Length implements Document.
func (d *document) Length(path string) int {
	n, err := valueAt(d.root, splitPath(path, d.separator))
	if err != nil {
		return -1
	}
	// Check if object or array.
	o, ok := isObject(n)
	if ok {
		return len(o)
	}
	a, ok := isArray(n)
	if ok {
		return len(a)
	}
	return 1
}

// SetValueAt implements Document.
func (d *document) SetValueAt(path string, value interface{}) error {
	parts := splitPath(path, d.separator)
	root, err := setValueAt(d.root, value, parts)
	if err != nil {
		return err
	}
	d.root = root
	return nil
}

// ValueAt implements Document.
func (d *document) ValueAt(path string) Value {
	n, err := valueAt(d.root, splitPath(path, d.separator))
	return &value{n, err}
}

// Clear implements Document.
func (d *document) Clear() {
	d.root = nil
}

// Query implements Document.
func (d *document) Query(pattern string) (PathValues, error) {
	pvs := PathValues{}
	err := d.Process(func(path string, value Value) error {
		if stringex.Matches(pattern, path, false) {
			pvs = append(pvs, PathValue{
				Path:  path,
				Value: value,
			})
		}
		return nil
	})
	return pvs, err
}

// Process implements Document.
func (d *document) Process(processor ValueProcessor) error {
	return process(d.root, []string{}, d.separator, processor)
}

// MarshalJSON implements json.Marshaler.
func (d *document) MarshalJSON() ([]byte, error) {
	return json.Marshal(d.root)
}

// EOF