Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix typos #82

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<p align="center">
<img
src="logo.png"
<img
src="logo.png"
width="240" height="78" border="0" alt="SJSON">
<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>
</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.
For quickly retrieving json values check out [GJSON](https://github.com/tidwall/gjson).
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 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).

Getting Started
===============
Expand All @@ -29,10 +29,10 @@ This will retrieve the library.

Set a value
-----------
Set sets the value for the specified path.
A path is in dot syntax, such as "name.last" or "age".
This function expects that the json is well-formed and validated.
Invalid json will not panic, but it may return back unexpected results.
Set sets the value for the specified path.
A path is in dot syntax, such as `name.last` or `age`.
This function expects that the JSON is well-formed and validated.
Invalid JSON will not panic, but it may return unexpected results.
Invalid paths may return an error.

```go
Expand Down Expand Up @@ -117,7 +117,7 @@ sjson.Set(`{"key":true}`, "key", []string{"hello", "world"})
sjson.Set(`{"key":true}`, "key", map[string]interface{}{"hello":"world"})
```

When a type is not recognized, SJSON will fallback to the `encoding/json` Marshaller.
When a type is not recognized, SJSON will fall back to the `encoding/json` Marshaler.


Examples
Expand Down Expand Up @@ -215,8 +215,8 @@ println(value)

## Performance

Benchmarks of SJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
[ffjson](https://github.com/pquerna/ffjson),
Benchmarks of SJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
[ffjson](https://github.com/pquerna/ffjson),
[EasyJSON](https://github.com/mailru/easyjson),
and [Gabs](https://github.com/Jeffail/gabs)

Expand All @@ -242,7 +242,7 @@ JSON document used:
"width": 500,
"height": 500
},
"image": {
"image": {
"src": "Images/Sun.png",
"hOffset": 250,
"vOffset": 250,
Expand All @@ -257,7 +257,7 @@ JSON document used:
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}
}
}
```

Each operation was rotated though one of the following search paths:
Expand All @@ -268,7 +268,7 @@ widget.image.hOffset
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 found [here](https://github.com/tidwall/sjson-benchmarks)*.

## Contact
Josh Baker [@tidwall](http://twitter.com/tidwall)
Expand Down
97 changes: 52 additions & 45 deletions sjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ type Options struct {
// Optimistic is a hint that the value likely exists which
// allows for the sjson to perform a fast-track search and replace.
Optimistic bool
// ReplaceInPlace is a hint to replace the input json rather than
// allocate a new json byte slice. When this field is specified
// the input json will not longer be valid and it should not be used
// ReplaceInPlace is a hint to replace the input JSON rather than
// allocate a new JSON byte slice. When this field is specified
// the input JSON will no longer be valid, and it should not be used
// In the case when the destination slice doesn't have enough free
// bytes to replace the data in place, a new bytes slice will be
// created under the hood.
// The Optimistic flag must be set to true and the input must be a
// byte slice in order to use this field.
// byte slice to use this field.
ReplaceInPlace bool
}

Expand Down Expand Up @@ -120,7 +120,7 @@ func mustMarshalString(s string) bool {
return false
}

// appendStringify makes a json string and appends to buf.
// appendStringify makes a JSON string and appends to buf.
func appendStringify(buf []byte, s string) []byte {
if mustMarshalString(s) {
b, _ := jsongo.Marshal(s)
Expand All @@ -132,9 +132,10 @@ func appendStringify(buf []byte, s string) []byte {
return buf
}

// 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,
stringify bool) []byte {
stringify bool,
) []byte {
if !array {
buf = appendStringify(buf, paths[0].part)
buf = append(buf, ':')
Expand All @@ -161,7 +162,7 @@ func appendBuild(buf []byte, array bool, paths []pathResult, raw string,
return buf
}

// atoui does a rip conversion of string -> unigned int.
// atoui does a rip conversion of string -> unsigned int.
func atoui(r pathResult) (n int, ok bool) {
if r.force {
return 0, false
Expand Down Expand Up @@ -248,7 +249,8 @@ loop:
var errNoChange = &errorType{"no change"}

func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
stringify, del bool) ([]byte, error) {
stringify, del bool,
) ([]byte, error) {
var err error
var res gjson.Result
var found bool
Expand Down Expand Up @@ -365,7 +367,8 @@ func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
} else {
return nil, &errorType{
"cannot set array element for non-numeric key '" +
paths[0].part + "'"}
paths[0].part + "'",
}
}
}
if appendit {
Expand Down Expand Up @@ -419,48 +422,47 @@ func isOptimisticPath(path string) bool {
return true
}

// Set sets a json value for the specified path.
// Set sets a JSON value for the specified path.
// A path is in dot syntax, such as "name.last" or "age".
// This function expects that the json is well-formed, and does not validate.
// Invalid json will not panic, but it may return back unexpected results.
// This function expects that the JSON is well-formed, and does not validate.
// Invalid JSON will not panic, but it may return unexpected results.
// An error is returned if the path is not valid.
//
// A path is a series of keys separated by a dot.
//
// {
// "name": {"first": "Tom", "last": "Anderson"},
// "age":37,
// "children": ["Sara","Alex","Jack"],
// "friends": [
// {"first": "James", "last": "Murphy"},
// {"first": "Roger", "last": "Craig"}
// ]
// }
// "name.last" >> "Anderson"
// "age" >> 37
// "children.1" >> "Alex"
//
// {
// "name": {"first": "Tom", "last": "Anderson"},
// "age":37,
// "children": ["Sara","Alex","Jack"],
// "friends": [
// {"first": "James", "last": "Murphy"},
// {"first": "Roger", "last": "Craig"}
// ]
// }
// "name.last" >> "Anderson"
// "age" >> 37
// "children.1" >> "Alex"
func Set(json, path string, value interface{}) (string, error) {
return SetOptions(json, path, value, nil)
}

// SetBytes sets a json value for the specified path.
// SetBytes sets a JSON value for the specified path.
// If working with bytes, this method preferred over
// Set(string(data), path, value)
func SetBytes(json []byte, path string, value interface{}) ([]byte, error) {
return SetBytesOptions(json, path, value, nil)
}

// SetRaw sets a raw json value for the specified path.
// SetRaw sets a raw JSON value for the specified path.
// This function works the same as Set except that the value is set as a
// raw block of json. This allows for setting premarshalled json objects.
// raw block of JSON. This allows for setting pre-marshaled JSON objects.
func SetRaw(json, path, value string) (string, error) {
return SetRawOptions(json, path, value, nil)
}

// SetRawOptions sets a raw json value for the specified path with options.
// This furnction works the same as SetOptions except that the value is set
// as a raw block of json. This allows for setting premarshalled json objects.
// SetRawOptions sets a raw JSON value for the specified path with options.
// This function works the same as SetOptions except that the value is set
// as a raw block of JSON. This allows for setting pre-marshaled JSON objects.
func SetRawOptions(json, path, value string, opts *Options) (string, error) {
var optimistic bool
if opts != nil {
Expand All @@ -473,7 +475,7 @@ func SetRawOptions(json, path, value string, opts *Options) (string, error) {
return string(res), err
}

// SetRawBytes sets a raw json value for the specified path.
// SetRawBytes sets a raw JSON value for the specified path.
// If working with bytes, this method preferred over
// SetRaw(string(data), path, value)
func SetRawBytes(json []byte, path string, value []byte) ([]byte, error) {
Expand All @@ -482,12 +484,12 @@ func SetRawBytes(json []byte, path string, value []byte) ([]byte, error) {

type dtype struct{}

// Delete deletes a value from json for the specified path.
// Delete deletes a value from JSON for the specified path.
func Delete(json, path string) (string, error) {
return Set(json, path, dtype{})
}

// DeleteBytes deletes a value from json for the specified path.
// DeleteBytes deletes a value from JSON for the specified path.
func DeleteBytes(json []byte, path string) ([]byte, error) {
return SetBytes(json, path, dtype{})
}
Expand All @@ -504,7 +506,8 @@ type sliceHeader struct {
}

func set(jstr, path, raw string,
stringify, del, optimistic, inplace bool) ([]byte, error) {
stringify, del, optimistic, inplace bool,
) ([]byte, error) {
if path == "" {
return []byte(jstr), &errorType{"path cannot be empty"}
}
Expand All @@ -519,7 +522,8 @@ func set(jstr, path, raw string,
if !stringify || !mustMarshalString(raw) {
jsonh := *(*stringHeader)(unsafe.Pointer(&jstr))
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))
if stringify {
jbytes[res.Index] = '"'
Expand Down Expand Up @@ -623,13 +627,14 @@ func setComplexPath(jstr, path, raw string, stringify bool) ([]byte, error) {
return []byte(jstr), nil
}

// SetOptions sets a json value for the specified path with options.
// SetOptions sets a JSON value for the specified path with options.
// A path is in dot syntax, such as "name.last" or "age".
// This function expects that the json is well-formed, and does not validate.
// Invalid json will not panic, but it may return back unexpected results.
// This function expects that the JSON is well-formed, and does not validate.
// Invalid JSON will not panic, but it may return unexpected results.
// An error is returned if the path is not valid.
func SetOptions(json, path string, value interface{},
opts *Options) (string, error) {
opts *Options,
) (string, error) {
if opts != nil {
if opts.ReplaceInPlace {
// it's not safe to replace bytes in-place for strings
Expand All @@ -646,11 +651,12 @@ func SetOptions(json, path string, value interface{},
return string(res), err
}

// SetBytesOptions sets a json value for the specified path with options.
// SetBytesOptions sets a JSON value for the specified path with options.
// If working with bytes, this method preferred over
// SetOptions(string(data), path, value)
func SetBytesOptions(json []byte, path string, value interface{},
opts *Options) ([]byte, error) {
opts *Options,
) ([]byte, error) {
var optimistic, inplace bool
if opts != nil {
optimistic = opts.Optimistic
Expand Down Expand Up @@ -717,11 +723,12 @@ func SetBytesOptions(json []byte, path string, value interface{},
return res, err
}

// SetRawBytesOptions sets a raw json value for the specified path with options.
// SetRawBytesOptions sets a raw JSON value for the specified path with options.
// If working with bytes, this method preferred over
// SetRawOptions(string(data), path, value, opts)
func SetRawBytesOptions(json []byte, path string, value []byte,
opts *Options) ([]byte, error) {
opts *Options,
) ([]byte, error) {
jstr := *(*string)(unsafe.Pointer(&json))
vstr := *(*string)(unsafe.Pointer(&value))
var optimistic, inplace bool
Expand Down
9 changes: 5 additions & 4 deletions sjson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

func TestBasic(t *testing.T) {
testRaw(t, setRaw, `[{"hiw":"planet","hi":"world"}]`, `[{"hi":"world"}]`, "0.hiw", `"planet"`)
testRaw(t, setRaw, `[true]`, ``, "0", `true`)
Expand Down Expand Up @@ -190,7 +191,7 @@ func TestDeleteIssue21(t *testing.T) {
expectedForLenBefore309AsBytes := `{"1":"","0":"01234567890123456789012345678901234567890123456789012345678901234567890123456","2":""}`
//---------------------------

var data = []struct {
data := []struct {
desc string
input string
expected string
Expand All @@ -214,7 +215,6 @@ func TestDeleteIssue21(t *testing.T) {

for i, d := range data {
result, err := Delete(d.input, "to_delete")

if err != nil {
t.Error(fmtErrorf(testError{
unexpected: "error",
Expand Down Expand Up @@ -270,6 +270,7 @@ func TestSetDotKeyIssue10(t *testing.T) {
t.Fatalf("expected '%v', got '%v'", `{"app.token":"cde"}`, json)
}
}

func TestDeleteDotKeyIssue19(t *testing.T) {
json := []byte(`{"data":{"key1":"value1","key2.something":"value2"}}`)
json, _ = DeleteBytes(json, `data.key2\.something`)
Expand All @@ -279,12 +280,12 @@ func TestDeleteDotKeyIssue19(t *testing.T) {
}

func TestIssue36(t *testing.T) {
var json = `
json := `
{
"size": 1000
}
`
var raw = `
raw := `
{
"sample": "hello"
}
Expand Down