forked from mirror/sjson
fix repos
This commit is contained in:
parent
b279807a1b
commit
a57b12847a
10
README.md
10
README.md
|
@ -3,13 +3,13 @@
|
||||||
src="logo.png"
|
src="logo.png"
|
||||||
width="240" height="78" border="0" alt="SJSON">
|
width="240" height="78" border="0" alt="SJSON">
|
||||||
<br>
|
<br>
|
||||||
<a href="https://godoc.org/github.com/tidwall/sjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
<a href="https://godoc.org/git.internal/re/sjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">set a json value quickly</p>
|
<p align="center">set a json value quickly</p>
|
||||||
|
|
||||||
SJSON is a Go package that provides a [very fast](#performance) and simple way to set a value in a json document.
|
SJSON is a Go package that provides a [very fast](#performance) and simple way to set a value in a json document.
|
||||||
For quickly retrieving json values check out [GJSON](https://github.com/tidwall/gjson).
|
For quickly retrieving json values check out [GJSON](https://git.internal/re/gjson).
|
||||||
|
|
||||||
For a command line interface check out [JJ](https://github.com/tidwall/jj).
|
For a command line interface check out [JJ](https://github.com/tidwall/jj).
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ Installing
|
||||||
To start using SJSON, install Go and run `go get`:
|
To start using SJSON, install Go and run `go get`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ go get -u github.com/tidwall/sjson
|
$ go get -u git.internal/re/sjson
|
||||||
```
|
```
|
||||||
|
|
||||||
This will retrieve the library.
|
This will retrieve the library.
|
||||||
|
@ -38,7 +38,7 @@ Invalid paths may return an error.
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/tidwall/sjson"
|
import "git.internal/re/sjson"
|
||||||
|
|
||||||
const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
|
const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ widget.image.hOffset
|
||||||
widget.text.onMouseUp
|
widget.text.onMouseUp
|
||||||
```
|
```
|
||||||
|
|
||||||
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7 and can be be found [here](https://github.com/tidwall/sjson-benchmarks)*.
|
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7 and can be be found [here](https://git.internal/re/sjson-benchmarks)*.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -1,8 +1,8 @@
|
||||||
module github.com/tidwall/sjson
|
module git.internal/re/sjson
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/tidwall/gjson v1.14.2
|
git.internal/re/gjson v1.14.4
|
||||||
github.com/tidwall/pretty v1.2.0
|
github.com/tidwall/pretty v1.2.0
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
||||||
github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo=
|
git.internal/re/gjson v1.14.4 h1:h247IjFbi0EbPbaP9uhmjF4d4BBZdzp3IqVdPbOfNlQ=
|
||||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
git.internal/re/gjson v1.14.4/go.mod h1:nWhPHhrw7k8ssdzMTMcw6ButkZOJV9xeqauMiGbDEmo=
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
|
|
51
sjson.go
51
sjson.go
|
@ -7,7 +7,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
"git.internal/re/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type errorType struct {
|
type errorType struct {
|
||||||
|
@ -134,7 +134,8 @@ func appendStringify(buf []byte, s string) []byte {
|
||||||
|
|
||||||
// appendBuild builds a json block from a json path.
|
// appendBuild builds a json block from a json path.
|
||||||
func appendBuild(buf []byte, array bool, paths []pathResult, raw string,
|
func appendBuild(buf []byte, array bool, paths []pathResult, raw string,
|
||||||
stringify bool) []byte {
|
stringify bool,
|
||||||
|
) []byte {
|
||||||
if !array {
|
if !array {
|
||||||
buf = appendStringify(buf, paths[0].part)
|
buf = appendStringify(buf, paths[0].part)
|
||||||
buf = append(buf, ':')
|
buf = append(buf, ':')
|
||||||
|
@ -248,7 +249,8 @@ loop:
|
||||||
var errNoChange = &errorType{"no change"}
|
var errNoChange = &errorType{"no change"}
|
||||||
|
|
||||||
func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
|
func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
|
||||||
stringify, del bool) ([]byte, error) {
|
stringify, del bool,
|
||||||
|
) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
var res gjson.Result
|
var res gjson.Result
|
||||||
var found bool
|
var found bool
|
||||||
|
@ -365,7 +367,8 @@ func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
|
||||||
} else {
|
} else {
|
||||||
return nil, &errorType{
|
return nil, &errorType{
|
||||||
"cannot set array element for non-numeric key '" +
|
"cannot set array element for non-numeric key '" +
|
||||||
paths[0].part + "'"}
|
paths[0].part + "'",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if appendit {
|
if appendit {
|
||||||
|
@ -427,19 +430,18 @@ func isOptimisticPath(path string) bool {
|
||||||
//
|
//
|
||||||
// A path is a series of keys separated by a dot.
|
// A path is a series of keys separated by a dot.
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// "name": {"first": "Tom", "last": "Anderson"},
|
// "name": {"first": "Tom", "last": "Anderson"},
|
||||||
// "age":37,
|
// "age":37,
|
||||||
// "children": ["Sara","Alex","Jack"],
|
// "children": ["Sara","Alex","Jack"],
|
||||||
// "friends": [
|
// "friends": [
|
||||||
// {"first": "James", "last": "Murphy"},
|
// {"first": "James", "last": "Murphy"},
|
||||||
// {"first": "Roger", "last": "Craig"}
|
// {"first": "Roger", "last": "Craig"}
|
||||||
// ]
|
// ]
|
||||||
// }
|
// }
|
||||||
// "name.last" >> "Anderson"
|
// "name.last" >> "Anderson"
|
||||||
// "age" >> 37
|
// "age" >> 37
|
||||||
// "children.1" >> "Alex"
|
// "children.1" >> "Alex"
|
||||||
//
|
|
||||||
func Set(json, path string, value interface{}) (string, error) {
|
func Set(json, path string, value interface{}) (string, error) {
|
||||||
return SetOptions(json, path, value, nil)
|
return SetOptions(json, path, value, nil)
|
||||||
}
|
}
|
||||||
|
@ -504,7 +506,8 @@ type sliceHeader struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func set(jstr, path, raw string,
|
func set(jstr, path, raw string,
|
||||||
stringify, del, optimistic, inplace bool) ([]byte, error) {
|
stringify, del, optimistic, inplace bool,
|
||||||
|
) ([]byte, error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return []byte(jstr), &errorType{"path cannot be empty"}
|
return []byte(jstr), &errorType{"path cannot be empty"}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +522,8 @@ func set(jstr, path, raw string,
|
||||||
if !stringify || !mustMarshalString(raw) {
|
if !stringify || !mustMarshalString(raw) {
|
||||||
jsonh := *(*stringHeader)(unsafe.Pointer(&jstr))
|
jsonh := *(*stringHeader)(unsafe.Pointer(&jstr))
|
||||||
jsonbh := sliceHeader{
|
jsonbh := sliceHeader{
|
||||||
data: jsonh.data, len: jsonh.len, cap: jsonh.len}
|
data: jsonh.data, len: jsonh.len, cap: jsonh.len,
|
||||||
|
}
|
||||||
jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh))
|
jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh))
|
||||||
if stringify {
|
if stringify {
|
||||||
jbytes[res.Index] = '"'
|
jbytes[res.Index] = '"'
|
||||||
|
@ -629,7 +633,8 @@ func setComplexPath(jstr, path, raw string, stringify bool) ([]byte, error) {
|
||||||
// Invalid json will not panic, but it may return back unexpected results.
|
// Invalid json will not panic, but it may return back unexpected results.
|
||||||
// An error is returned if the path is not valid.
|
// An error is returned if the path is not valid.
|
||||||
func SetOptions(json, path string, value interface{},
|
func SetOptions(json, path string, value interface{},
|
||||||
opts *Options) (string, error) {
|
opts *Options,
|
||||||
|
) (string, error) {
|
||||||
if opts != nil {
|
if opts != nil {
|
||||||
if opts.ReplaceInPlace {
|
if opts.ReplaceInPlace {
|
||||||
// it's not safe to replace bytes in-place for strings
|
// it's not safe to replace bytes in-place for strings
|
||||||
|
@ -650,7 +655,8 @@ func SetOptions(json, path string, value interface{},
|
||||||
// If working with bytes, this method preferred over
|
// If working with bytes, this method preferred over
|
||||||
// SetOptions(string(data), path, value)
|
// SetOptions(string(data), path, value)
|
||||||
func SetBytesOptions(json []byte, path string, value interface{},
|
func SetBytesOptions(json []byte, path string, value interface{},
|
||||||
opts *Options) ([]byte, error) {
|
opts *Options,
|
||||||
|
) ([]byte, error) {
|
||||||
var optimistic, inplace bool
|
var optimistic, inplace bool
|
||||||
if opts != nil {
|
if opts != nil {
|
||||||
optimistic = opts.Optimistic
|
optimistic = opts.Optimistic
|
||||||
|
@ -721,7 +727,8 @@ func SetBytesOptions(json []byte, path string, value interface{},
|
||||||
// If working with bytes, this method preferred over
|
// If working with bytes, this method preferred over
|
||||||
// SetRawOptions(string(data), path, value, opts)
|
// SetRawOptions(string(data), path, value, opts)
|
||||||
func SetRawBytesOptions(json []byte, path string, value []byte,
|
func SetRawBytesOptions(json []byte, path string, value []byte,
|
||||||
opts *Options) ([]byte, error) {
|
opts *Options,
|
||||||
|
) ([]byte, error) {
|
||||||
jstr := *(*string)(unsafe.Pointer(&json))
|
jstr := *(*string)(unsafe.Pointer(&json))
|
||||||
vstr := *(*string)(unsafe.Pointer(&value))
|
vstr := *(*string)(unsafe.Pointer(&value))
|
||||||
var optimistic, inplace bool
|
var optimistic, inplace bool
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
"git.internal/re/gjson"
|
||||||
"github.com/tidwall/pretty"
|
"github.com/tidwall/pretty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ func testRaw(t *testing.T, kind int, expect, json, path string, value interface{
|
||||||
t.Fatalf("expected '%v', got '%v'", expect, string(json3))
|
t.Fatalf("expected '%v', got '%v'", expect, string(json3))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
testRaw(t, setRaw, `[{"hiw":"planet","hi":"world"}]`, `[{"hi":"world"}]`, "0.hiw", `"planet"`)
|
testRaw(t, setRaw, `[{"hiw":"planet","hi":"world"}]`, `[{"hi":"world"}]`, "0.hiw", `"planet"`)
|
||||||
testRaw(t, setRaw, `[true]`, ``, "0", `true`)
|
testRaw(t, setRaw, `[true]`, ``, "0", `true`)
|
||||||
|
@ -190,7 +191,7 @@ func TestDeleteIssue21(t *testing.T) {
|
||||||
expectedForLenBefore309AsBytes := `{"1":"","0":"01234567890123456789012345678901234567890123456789012345678901234567890123456","2":""}`
|
expectedForLenBefore309AsBytes := `{"1":"","0":"01234567890123456789012345678901234567890123456789012345678901234567890123456","2":""}`
|
||||||
//---------------------------
|
//---------------------------
|
||||||
|
|
||||||
var data = []struct {
|
data := []struct {
|
||||||
desc string
|
desc string
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
|
@ -214,7 +215,6 @@ func TestDeleteIssue21(t *testing.T) {
|
||||||
|
|
||||||
for i, d := range data {
|
for i, d := range data {
|
||||||
result, err := Delete(d.input, "to_delete")
|
result, err := Delete(d.input, "to_delete")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(fmtErrorf(testError{
|
t.Error(fmtErrorf(testError{
|
||||||
unexpected: "error",
|
unexpected: "error",
|
||||||
|
@ -270,6 +270,7 @@ func TestSetDotKeyIssue10(t *testing.T) {
|
||||||
t.Fatalf("expected '%v', got '%v'", `{"app.token":"cde"}`, json)
|
t.Fatalf("expected '%v', got '%v'", `{"app.token":"cde"}`, json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteDotKeyIssue19(t *testing.T) {
|
func TestDeleteDotKeyIssue19(t *testing.T) {
|
||||||
json := []byte(`{"data":{"key1":"value1","key2.something":"value2"}}`)
|
json := []byte(`{"data":{"key1":"value1","key2.something":"value2"}}`)
|
||||||
json, _ = DeleteBytes(json, `data.key2\.something`)
|
json, _ = DeleteBytes(json, `data.key2\.something`)
|
||||||
|
@ -279,12 +280,12 @@ func TestDeleteDotKeyIssue19(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue36(t *testing.T) {
|
func TestIssue36(t *testing.T) {
|
||||||
var json = `
|
json := `
|
||||||
{
|
{
|
||||||
"size": 1000
|
"size": 1000
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
var raw = `
|
raw := `
|
||||||
{
|
{
|
||||||
"sample": "hello"
|
"sample": "hello"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue