Skip to content

Commit

Permalink
🐛 Fix jMap struct field tags preserved. (#652)
Browse files Browse the repository at this point in the history
Bug: File reaper json query:
```
SELECT count(*) 
FROM `Task` ,json_each(Attached) j0 
WHERE json_extract(j0.value,'$.id')=file.pk
```
not finding references which result in false orphans.

Fix:
Ensure struct tags are honored and preserved by jMap. For Attachments:
```
[
{"Activity":9,"ID":351,"Name":"ssh-agent.output"},
{"Activity":14,"ID":352,"Name":"git.output"},
{"Activity":19,"ID":353,"Name":"windup-shim.output"},
{"Activity":20,"ID":354,"Name":"settings.yaml"},
{"Activity":21,"ID":355,"Name":"konveyor-analyzer.output"},
{"Activity":23,"ID":356,"Name":"konveyor-analyzer-dep.output"}
]
```
MUST be stored as (with lower-case keys):
```
[
{"activity":9,"id":351,"name":"ssh-agent.output"},
{"activity":14,"id":352,"name":"git.output"},
{"activity":19,"id":353,"name":"windup-shim.output"},
{"activity":20,"id":354,"name":"settings.yaml"},
{"activity":21,"id":355,"name":"konveyor-analyzer.output"},
{"activity":23,"id":356,"name":"konveyor-analyzer-dep.output"}
]
```
else not found.

---------

Signed-off-by: Jeff Ortel <[email protected]>
  • Loading branch information
jortel authored Jun 12, 2024
1 parent f0a064a commit f755888
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 17 deletions.
98 changes: 98 additions & 0 deletions model/model_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package model

import (
"encoding/json"
"testing"

"github.com/onsi/gomega"
)

func TestMapMap(t *testing.T) {
g := gomega.NewGomegaWithT(t)
js := jsonSerializer{}
in := map[any]any{
0: "A",
"1": "B",
}
out := js.jMap(in)
mp, cast := out.(map[string]any)
g.Expect(cast).To(gomega.BeTrue())
g.Expect(len(mp)).To(gomega.Equal(len(in)))
g.Expect(mp["0"]).To(gomega.Equal(in[0]))
}

func TestMapArrayStruct(t *testing.T) {
g := gomega.NewGomegaWithT(t)
js := jsonSerializer{}
in := []Attachment{
{ID: 1, Activity: 18},
{ID: 2, Activity: 48},
}
out := js.jMap(in)
list, cast := out.([]any)
g.Expect(cast).To(gomega.BeTrue())
g.Expect(len(list)).To(gomega.Equal(len(in)))
g.Expect(list[0].(Attachment).ID).To(gomega.Equal(in[0].ID))
g.Expect(list[1].(Attachment).ID).To(gomega.Equal(in[1].ID))
g.Expect(list[0].(Attachment).Activity).To(gomega.Equal(in[0].Activity))
g.Expect(list[1].(Attachment).Activity).To(gomega.Equal(in[1].Activity))

m, err := json.Marshal(list[0])
g.Expect(err).To(gomega.BeNil())
m2 := make(map[string]any)
err = json.Unmarshal(m, &m2)
g.Expect(err).To(gomega.BeNil())
g.Expect(m2["id"]).To(gomega.Equal(float64(1)))
g.Expect(m2["activity"]).To(gomega.Equal(float64(18)))
}

func TestMapData(t *testing.T) {
g := gomega.NewGomegaWithT(t)
js := jsonSerializer{}
in := Data{
Any: map[any]any{
0: "A",
"1": "B",
},
}
out := js.jMap(in)
d, cast := out.(Data)
g.Expect(cast).To(gomega.BeTrue())
dAny, cast := d.Any.(map[string]any)
g.Expect(cast).To(gomega.BeTrue())
g.Expect(len(dAny)).To(gomega.Equal(2))
g.Expect(dAny["0"]).To(gomega.Equal(in.Any.(map[any]any)[0]))
g.Expect(dAny["1"]).To(gomega.Equal(in.Any.(map[any]any)["1"]))
}

func TestMapDataPtr(t *testing.T) {
g := gomega.NewGomegaWithT(t)
js := jsonSerializer{}
in := &Data{
Any: map[any]any{
0: "A",
"1": "B",
2: Data{
Any: map[any]any{
2: "2A",
"3": "3B",
},
},
},
}
out := js.jMap(in)
d, cast := out.(Data)
g.Expect(cast).To(gomega.BeTrue())
dAny, cast := d.Any.(map[string]any)
g.Expect(cast).To(gomega.BeTrue())
g.Expect(len(dAny)).To(gomega.Equal(3))
g.Expect(dAny["0"]).To(gomega.Equal(in.Any.(map[any]any)[0]))
g.Expect(dAny["1"]).To(gomega.Equal(in.Any.(map[any]any)["1"]))
d2Any := dAny["2"]
d2d, cast := d2Any.(Data)
g.Expect(cast).To(gomega.BeTrue())
d2dAny, cast := d2d.Any.(map[string]any)
g.Expect(cast).To(gomega.BeTrue())
g.Expect(d2dAny["2"]).To(gomega.Equal("2A"))
g.Expect(d2dAny["3"]).To(gomega.Equal("3B"))
}
35 changes: 18 additions & 17 deletions model/serializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,35 @@ func (r jsonSerializer) jMap(in any) (out any) {
}
switch t.Kind() {
case reflect.Struct:
mp := make(map[string]any)
out = reflect.New(t).Interface()
nt := reflect.TypeOf(out)
nt = nt.Elem()
nv := reflect.ValueOf(out)
nv = nv.Elem()
for i := 0; i < t.NumField(); i++ {
t := t.Field(i)
v := v.Field(i)
if !t.IsExported() {
ft := t.Field(i)
fv := v.Field(i)
if !ft.IsExported() {
continue
}
var object any
switch v.Kind() {
switch fv.Kind() {
case reflect.Ptr:
if !v.IsNil() {
object = v.Elem().Interface()
object = fv.Elem().Interface()
}
default:
object = v.Interface()
object = fv.Interface()
}
object = r.jMap(object)
if t.Anonymous {
if m, cast := object.(map[string]any); cast {
for k, v := range m {
mp[k] = v
}
}
} else {
mp[t.Name] = object
}
ft = nt.Field(i)
fv = nv.Field(i)
x := reflect.ValueOf(object)
fv.Set(x)
}
out = mp
v = reflect.ValueOf(out)
v = v.Elem()
out = v.Interface()
case reflect.Slice:
list := make([]any, 0)
for i := 0; i < v.Len(); i++ {
Expand Down

0 comments on commit f755888

Please sign in to comment.