Skip to content

Commit

Permalink
[+] feat: Add ExtractAll function
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-M-C committed Dec 18, 2024
1 parent 1dd5628 commit 07c749a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 6 deletions.
3 changes: 0 additions & 3 deletions any_ltgo17.go

This file was deleted.

58 changes: 55 additions & 3 deletions import_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,59 @@ func Import(src any, opts ...Option) (*V, error) {
return res, nil
}

// parserFunc 处理对应 reflect.Value 的函数
// ExtractAll firstly does Import, then checks all string-typed value. Once they
// could be successfully unmarshal again, they will be unmarshaled again until
// no sub-value could be unmarshaled any more.
//
// ExtractAll 首先执行 Import 操作, 然后再迭代检查所有 string 类型的值, 如果能够再成功执行
// unmarshal 操作, 则继续将这些值 unmarshal 掉。如此以往直至所有值均无法再反序列化。
func ExtractAll(src any, opts ...Option) (*V, error) {
v, err := Import(src, opts...)
if err != nil {
return v, err
}
return extractValue(v), nil
}

func extractValue(v *V) *V {
switch v.valueType {
case String:
return extractStringValue(v)
case Object:
return extractObjectValue(v)
case Array:
return extractArrayValue(v)
default:
return v
}
}

func extractStringValue(v *V) *V {
newV, err := UnmarshalString(v.valueStr)
if err != nil {
return v
}
return extractValue(newV)
}

func extractObjectValue(v *V) *V {
for key, subV := range v.children.object {
v.children.object[key] = childWithProperty{
id: subV.id,
v: extractValue(subV.v),
}
}
return v
}

func extractArrayValue(v *V) *V {
for i, subV := range v.children.arr {
v.children.arr[i] = extractValue(subV)
}
return v
}

// parserFunc handle functions operating various reflect.Value types
type parserFunc func(v reflect.Value, ex ext) (*V, error)

type ext struct {
Expand All @@ -61,7 +113,7 @@ func (e ext) shouldOmitEmpty() bool {
return e.omitempty || e.private
}

// validateValAndReturnParser 检查入参合法性并返回相应的处理函数
// validateValAndReturnParser checks incoming parameter and return corresponding handler
func validateValAndReturnParser(v reflect.Value, ex ext) (out reflect.Value, fu parserFunc, err error) {
out = v

Expand Down Expand Up @@ -138,7 +190,7 @@ func validateValAndReturnParser(v reflect.Value, ex ext) (out reflect.Value, fu
return
}

// Hit marshaler if fu is not nil.
// Get marshaler if fu is not nil.
func checkAndParseMarshaler(v reflect.Value) (out reflect.Value, fu parserFunc) {
out = v
if !v.IsValid() {
Expand Down
47 changes: 47 additions & 0 deletions import_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func testImportExport(t *testing.T) {
cv("test Issue 22", func() { testImportBugIssue22(t) })

cv("test miscellaneous anonymous situations", func() { testImportMiscAnonymous(t) })

cv("test ExtractAll", func() { testExtractAll(t) })
}

func testExportString(*testing.T) {
Expand Down Expand Up @@ -1381,3 +1383,48 @@ type refTextMarshaler struct {
func (r *refTextMarshaler) MarshalText() ([]byte, error) {
return []byte(r.s), nil
}

func testExtractAll(t *testing.T) {
cv("general situation", func() {
v := NewObject()
v.At("string").Set("hello, world")
v.At("int").Set("12345")
v.At("bool").Set(true)
v.At("array").Set([]any{`{"str_in_obj_in_arr":"sub_sub_str"}`})
t.Log(v.MustMarshalString())

v = New(map[string]any{"embeded": v.MustMarshalString()})
v = New(map[string]any{"embeded_again": v.MustMarshalString()})
t.Log(v.MustMarshalString()) // should contains "\\\""
_, err := v.Get("embeded_again", "embeded", "string")
so(err, isErr)

v, err = ExtractAll(v)
t.Log(v.MustMarshalString())
so(err, isNil)

subV, err := v.Get("embeded_again", "embeded", "string")
so(err, isNil)
so(subV.ValueType(), eq, String)
so(subV.String(), eq, "hello, world")

subV, err = v.Get("embeded_again", "embeded", "int")
so(err, isNil)
so(subV.ValueType(), eq, Number)
so(subV.Int(), eq, 12345)

subV, err = v.Get("embeded_again", "embeded", "array", 0, "str_in_obj_in_arr")
so(err, isNil)
so(subV.ValueType(), eq, String)
so(subV.String(), eq, "sub_sub_str")
})

cv("extact error", func() {
ch := make(chan bool)
defer close(ch)

v, err := ExtractAll(ch)
so(err, isErr)
so(v, notNil)
})
}
2 changes: 2 additions & 0 deletions jsonvalue.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ const (
Unknown
)

type any = interface{}

var typeStr = [Unknown + 1]string{
"illegal",
"string",
Expand Down

0 comments on commit 07c749a

Please sign in to comment.