Skip to content

Commit 9b472af

Browse files
authored
Merge pull request #250 from goccy/feature/json-path
Support JSON Path for decoding
2 parents d7c473e + 781a0b3 commit 9b472af

30 files changed

+1818
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ cover-html: cover
2222

2323
.PHONY: lint
2424
lint: golangci-lint
25-
golangci-lint run
25+
$(BIN_DIR)/golangci-lint run
2626

2727
golangci-lint: | $(BIN_DIR)
2828
@{ \

benchmarks/path_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package benchmark
2+
3+
import (
4+
"testing"
5+
6+
gojson "github.com/goccy/go-json"
7+
)
8+
9+
func Benchmark_Decode_SmallStruct_UnmarshalPath_GoJson(b *testing.B) {
10+
path, err := gojson.CreatePath("$.st")
11+
if err != nil {
12+
b.Fatal(err)
13+
}
14+
b.ReportAllocs()
15+
for i := 0; i < b.N; i++ {
16+
var v int
17+
if err := path.Unmarshal(SmallFixture, &v); err != nil {
18+
b.Fatal(err)
19+
}
20+
if v != 1 {
21+
b.Fatal("failed to unmarshal path")
22+
}
23+
}
24+
}

decode.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,34 @@ func unmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs
8383
return validateEndBuf(src, cursor)
8484
}
8585

86+
var (
87+
pathDecoder = decoder.NewPathDecoder()
88+
)
89+
90+
func extractFromPath(path *Path, data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) {
91+
src := make([]byte, len(data)+1) // append nul byte to the end
92+
copy(src, data)
93+
94+
ctx := decoder.TakeRuntimeContext()
95+
ctx.Buf = src
96+
ctx.Option.Flags = 0
97+
ctx.Option.Flags |= decoder.PathOption
98+
ctx.Option.Path = path.path
99+
for _, optFunc := range optFuncs {
100+
optFunc(ctx.Option)
101+
}
102+
paths, cursor, err := pathDecoder.DecodePath(ctx, 0, 0)
103+
if err != nil {
104+
decoder.ReleaseRuntimeContext(ctx)
105+
return nil, err
106+
}
107+
decoder.ReleaseRuntimeContext(ctx)
108+
if err := validateEndBuf(src, cursor); err != nil {
109+
return nil, err
110+
}
111+
return paths, nil
112+
}
113+
86114
func unmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
87115
src := make([]byte, len(data)+1) // append nul byte to the end
88116
copy(src, data)

error.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ type UnmarshalTypeError = errors.UnmarshalTypeError
3737
type UnsupportedTypeError = errors.UnsupportedTypeError
3838

3939
type UnsupportedValueError = errors.UnsupportedValueError
40+
41+
type PathError = errors.PathError

internal/decoder/anonymous_field.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ func (d *anonymousFieldDecoder) Decode(ctx *RuntimeContext, cursor, depth int64,
3535
p = *(*unsafe.Pointer)(p)
3636
return d.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset))
3737
}
38+
39+
func (d *anonymousFieldDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
40+
return d.dec.DecodePath(ctx, cursor, depth)
41+
}

internal/decoder/array.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package decoder
22

33
import (
4+
"fmt"
45
"unsafe"
56

67
"github.com/goccy/go-json/internal/errors"
@@ -167,3 +168,7 @@ func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe
167168
}
168169
}
169170
}
171+
172+
func (d *arrayDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
173+
return nil, 0, fmt.Errorf("json: array decoder does not support decode path")
174+
}

0 commit comments

Comments
 (0)