Skip to content

Commit

Permalink
support tag
Browse files Browse the repository at this point in the history
  • Loading branch information
rot1024 committed Dec 22, 2023
1 parent 59a73f0 commit 76280be
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 29 deletions.
54 changes: 48 additions & 6 deletions go/marshaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"reflect"
"strings"

"github.com/samber/lo"
"golang.org/x/exp/slices"
)

Expand Down Expand Up @@ -57,7 +58,7 @@ func (d *Item) Unmarshal(i any) {
}
}

groups := make([]Item, 0, len(groupIDs))
groups := make([]*Item, 0, len(groupIDs))
for _, g := range groupIDs {
group := d.Group(g)
groups = append(groups, group)
Expand Down Expand Up @@ -104,6 +105,27 @@ func (d *Item) Unmarshal(i any) {
continue
}

// Tag
assignIf[Tag](vf, func() (Tag, bool) {
t := TagFrom(itf.Value)
if t == nil {
return Tag{}, false
}
return *t, true
})
assignIf[[]Tag](vf, func() ([]Tag, bool) {
return TagsFrom(itf.Value), true
})
assignIf[[]*Tag](vf, func() ([]*Tag, bool) {
return lo.ToSlicePtr(TagsFrom(itf.Value)), true
})

// Value
assignIf[Value](vf, func() (Value, bool) {
return *NewValue(itf.Value), true
})

// normal value
itfv := reflect.ValueOf(itf.Value)
if iftvt := reflect.TypeOf(itf.Value); iftvt != nil && iftvt.AssignableTo(vf.Type()) {
vf.Set(itfv)
Expand All @@ -113,17 +135,34 @@ func (d *Item) Unmarshal(i any) {
}
}

func Marshal(i any, item *Item) {
if item == nil || i == nil {
func assignIf[T any](vf reflect.Value, conv func() (T, bool)) {
var t T
if valueType := reflect.TypeOf(&t); vf.Type().AssignableTo(valueType) {
v, ok := conv()
if !ok {
return
}
vf.Set(reflect.ValueOf(lo.ToPtr(v)))
} else if valueType := reflect.TypeOf(t); vf.Type().AssignableTo(valueType) {
v, ok := conv()
if !ok {
return
}
vf.Set(reflect.ValueOf(v))
}
}

func Marshal(src any, item *Item) {
if item == nil || src == nil {
return
}

t := reflect.TypeOf(i)
t := reflect.TypeOf(src)
if t == nil {
return
}

v := reflect.ValueOf(i)
v := reflect.ValueOf(src)
if t.Kind() == reflect.Pointer {
if v.IsNil() {
return
Expand All @@ -140,6 +179,7 @@ func Marshal(i any, item *Item) {
f := t.Field(i)
tag := f.Tag.Get(tag)
key, opts, _ := strings.Cut(tag, ",")

if key == "" || key == "-" {
continue
}
Expand All @@ -157,7 +197,9 @@ func Marshal(i any, item *Item) {

vft := vf.Type()
var value any
if vft.Kind() == reflect.Slice && vft.Elem().Kind() == reflect.String && vf.Len() > 0 {
if m, ok := vf.Interface().(MarshalCMS); ok {
value = m.MarshalCMS()
} else if vft.Kind() == reflect.Slice && vft.Elem().Kind() == reflect.String && vf.Len() > 0 {
st := reflect.TypeOf("")
v := make([]string, 0, vf.Len())
for i := 0; i < cap(v); i++ {
Expand Down
12 changes: 12 additions & 0 deletions go/marshaling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ func TestItem_Unmarshal(t *testing.T) {
GGG []*G `cms:"ggg,group"`
HHH []G `cms:"hhh,group"`
III *int `cms:"iii,,metadata,includezero"`
JJJ []Tag `cms:"jjj"`
KKK *Value `cms:"kkk"`
}
s := S{}

Expand All @@ -38,6 +40,8 @@ func TestItem_Unmarshal(t *testing.T) {
{Key: "hhh", Type: "group", Value: []string{"1"}},
{Key: "aaa", Group: "1", Value: "123"},
{Key: "iii"},
{Key: "jjj", Value: []any{map[string]any{"id": "xxx", "name": "tag"}}},
{Key: "kkk", Value: []any{map[string]any{"id": "xxx", "name": "tag"}}},
},
MetadataFields: []*Field{
{Key: "eee", Value: true},
Expand All @@ -54,6 +58,8 @@ func TestItem_Unmarshal(t *testing.T) {
GGG: []*G{{ID: "1", AAA: "123"}, {ID: "2"}},
HHH: []G{{ID: "1", AAA: "123"}},
III: nil,
JJJ: []Tag{{ID: "xxx", Name: "tag"}},
KKK: &Value{value: []any{map[string]any{"id": "xxx", "name": "tag"}}},
}, s)

// no panic
Expand All @@ -80,6 +86,8 @@ func TestMarshal(t *testing.T) {
GGG []G `cms:"ggg"`
HHH []*G `cms:"hhh"`
III *int `cms:"iii,,metadata,includezero"`
JJJ *Value `cms:"jjj"`
KKK *Tag `cms:"kkk"`
}

s := S{
Expand All @@ -91,6 +99,8 @@ func TestMarshal(t *testing.T) {
FFF: true,
GGG: []G{{ID: "1", AAA: "ggg"}},
HHH: []*G{{ID: "2", AAA: "hhh"}, nil},
JJJ: &Value{value: "foo"},
KKK: &Tag{ID: "tag"},
}

expected := &Item{
Expand All @@ -105,6 +115,8 @@ func TestMarshal(t *testing.T) {
{Key: "ggg", Type: "group", Value: []string{"1"}},
{Key: "aaa", Group: "2", Type: "text", Value: "hhh"},
{Key: "hhh", Type: "group", Value: []string{"2"}},
{Key: "jjj", Type: "", Value: "foo"},
{Key: "kkk", Type: "", Value: "tag"},
},
MetadataFields: []*Field{
{Key: "fff", Type: "bool", Value: true},
Expand Down
4 changes: 2 additions & 2 deletions go/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (i *Item) MetadataFieldByKeyAndGroup(key, group string) *Field {
return nil
}

func (i *Item) Group(g string) Item {
func (i *Item) Group(g string) *Item {
fields := lo.Map(lo.Filter(i.Fields, func(f *Field, _ int) bool {
return f.Group == g
}), func(f *Field, _ int) *Field {
Expand All @@ -204,7 +204,7 @@ func (i *Item) Group(g string) Item {
return g
})

return Item{
return &Item{
ID: g,
ModelID: i.ModelID,
Fields: fields,
Expand Down
2 changes: 1 addition & 1 deletion go/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestItem_Group(t *testing.T) {
}

g := item.Group("1")
assert.Equal(t, Item{
assert.Equal(t, &Item{
ID: "1",
ModelID: "xxx",
Fields: []*Field{
Expand Down
81 changes: 61 additions & 20 deletions go/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (
"github.com/samber/lo"
)

type MarshalCMS interface {
MarshalCMS() any
}

type Tag struct {
ID string `json:"id"`
Name string `json:"name"`
Expand All @@ -32,6 +36,33 @@ func TagFrom(j any) *Tag {
return &t
}

func TagsFrom(j any) []Tag {
s, ok := j.([]any)
if !ok {
s2, ok := j.([]map[string]any)
if !ok {
return nil
}
s = make([]any, len(s2))
for i, e := range s2 {
s[i] = e
}
}

res := make([]Tag, len(s))
for i, e := range s {
if t := TagFrom(e); t != nil {
res[i] = *t
}
}

return res
}

func (t Tag) MarshalCMS() any {
return t.ID
}

type Value struct {
value any
}
Expand Down Expand Up @@ -87,27 +118,10 @@ func (v *Value) Tag() *Tag {
}

func (v *Value) Tags() []Tag {
values, ok := v.value.([]any)
if !ok {
values2, ok := v.value.([]map[string]any)
if !ok {
return nil
}

values = make([]any, len(values2))
for i, value := range values2 {
values[i] = value
}
}

res := make([]Tag, len(values))
for i, value := range values {
if t := TagFrom(value); t != nil {
res[i] = *t
}
if v == nil {
return nil
}

return res
return TagsFrom(v.value)
}

func (f *Value) JSON(j any) error {
Expand Down Expand Up @@ -169,6 +183,33 @@ func getValue[T any](v *Value) *T {
return nil
}

func (v *Value) MarshalCMS() any {
if v == nil {
return nil
}
if m, ok := v.value.(MarshalCMS); ok {
return m.MarshalCMS()
}
return v.value
}

func (v *Value) MarshalJSON() ([]byte, error) {
if v == nil {
return nil, nil
}
return json.Marshal(v.value)
}

func (v *Value) UnmarshalJSON(b []byte) error {
if v == nil {
*v = Value{}
}
if err := json.Unmarshal(b, &v.value); err != nil {
return err
}
return nil
}

func getValues[T any](v *Value) []T {
if v == nil {
return nil
Expand Down

0 comments on commit 76280be

Please sign in to comment.