diff --git a/cloudfirestore/batch_getter_impl.go b/cloudfirestore/batch_getter_impl.go index 02508ed..e1b10f2 100644 --- a/cloudfirestore/batch_getter_impl.go +++ b/cloudfirestore/batch_getter_impl.go @@ -97,8 +97,9 @@ func (bg *batchGetter) commit(ctx context.Context) error { log.Error(ctx, err) return err } - setDocByDst(dst, dsnp.Ref) - setEmptyBySlice(dst) + SetDocByDst(dst, dsnp.Ref) + SetEmptyBySlice(dst) + SetEmptyByMap(dst) } return nil } diff --git a/cloudfirestore/helper.go b/cloudfirestore/helper.go index b4db0b5..beab6cb 100644 --- a/cloudfirestore/helper.go +++ b/cloudfirestore/helper.go @@ -110,8 +110,9 @@ func Get(ctx context.Context, docRef *firestore.DocumentRef, dst any) (bool, err log.Error(ctx, err) return false, err } - setDocByDst(dst, dsnp.Ref) - setEmptyBySlice(dst) + SetDocByDst(dst, dsnp.Ref) + SetEmptyBySlice(dst) + SetEmptyByMap(dst) return true, nil } @@ -149,8 +150,9 @@ func GetMulti(ctx context.Context, cFirestore *firestore.Client, docRefs []*fire return err } rrv := reflect.ValueOf(v) - setDocByDsts(rrv, rrt, dsnp.Ref) - setEmptyBySlices(rrv, rrt) + SetDocByDsts(rrv, rrt, dsnp.Ref) + SetEmptyBySlices(rrv, rrt) + SetEmptyByMaps(rrv, rrt) rv.Set(reflect.Append(rv, rrv)) } return nil @@ -179,8 +181,9 @@ func GetByQuery(ctx context.Context, query firestore.Query, dst any) (bool, erro log.Error(ctx, err) return false, err } - setDocByDst(dst, dsnp.Ref) - setEmptyBySlice(dst) + SetDocByDst(dst, dsnp.Ref) + SetEmptyBySlice(dst) + SetEmptyByMap(dst) return true, nil } @@ -211,8 +214,9 @@ func ListByQuery(ctx context.Context, query firestore.Query, dsts any) error { return err } rrv := reflect.ValueOf(v) - setDocByDsts(rrv, rrt, dsnp.Ref) - setEmptyBySlices(rrv, rrt) + SetDocByDsts(rrv, rrt, dsnp.Ref) + SetEmptyBySlices(rrv, rrt) + SetEmptyByMaps(rrv, rrt) rv.Set(reflect.Append(rv, rrv)) } return nil @@ -250,8 +254,9 @@ func ListByQueryCursor(ctx context.Context, query firestore.Query, limit int, cu return nil, err } rrv := reflect.ValueOf(v) - setDocByDsts(rrv, rrt, dsnp.Ref) - setEmptyBySlices(rrv, rrt) + SetDocByDsts(rrv, rrt, dsnp.Ref) + SetEmptyBySlices(rrv, rrt) + SetEmptyByMaps(rrv, rrt) rv.Set(reflect.Append(rv, rrv)) lastDsnp = dsnp } @@ -267,7 +272,8 @@ func Create(ctx context.Context, colRef *firestore.CollectionRef, src any) error if !ValidateCollectionRef(colRef) { return errors.New("Invalid Collection Path: " + colRef.Path) } - setEmptyBySlice(src) + SetEmptyBySlice(src) + SetEmptyByMap(src) var docRef *firestore.DocumentRef if tx := getContextTransaction(ctx); tx != nil { id := stringutil.UniqueID() @@ -293,7 +299,7 @@ func Create(ctx context.Context, colRef *firestore.CollectionRef, src any) error return err } } - setDocByDst(src, docRef) + SetDocByDst(src, docRef) return nil } @@ -332,7 +338,8 @@ func Set(ctx context.Context, docRef *firestore.DocumentRef, src any) error { if !ValidateDocumentRef(docRef) { return errors.New("Invalid Document Path: " + docRef.Path) } - setEmptyBySlice(src) + SetEmptyBySlice(src) + SetEmptyByMap(src) if tx := getContextTransaction(ctx); tx != nil { err := tx.Set(docRef, src) if err != nil { @@ -352,7 +359,7 @@ func Set(ctx context.Context, docRef *firestore.DocumentRef, src any) error { return err } } - setDocByDst(src, docRef) + SetDocByDst(src, docRef) return nil } diff --git a/cloudfirestore/util.go b/cloudfirestore/util.go index 318bd7e..af7ccf8 100644 --- a/cloudfirestore/util.go +++ b/cloudfirestore/util.go @@ -6,7 +6,7 @@ import ( "cloud.google.com/go/firestore" ) -func setDocByDst(dst any, ref *firestore.DocumentRef) { +func SetDocByDst(dst any, ref *firestore.DocumentRef) { rv := reflect.Indirect(reflect.ValueOf(dst)) rt := rv.Type() if rt.Kind() == reflect.Struct { @@ -25,7 +25,7 @@ func setDocByDst(dst any, ref *firestore.DocumentRef) { } } -func setDocByDsts(rv reflect.Value, rt reflect.Type, ref *firestore.DocumentRef) { +func SetDocByDsts(rv reflect.Value, rt reflect.Type, ref *firestore.DocumentRef) { if rt.Kind() == reflect.Struct { for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) @@ -42,7 +42,7 @@ func setDocByDsts(rv reflect.Value, rt reflect.Type, ref *firestore.DocumentRef) } } -func setEmptyBySlice(dst any) { +func SetEmptyBySlice(dst any) { rv := reflect.Indirect(reflect.ValueOf(dst)) rt := rv.Type() if rt.Kind() == reflect.Struct { @@ -58,7 +58,7 @@ func setEmptyBySlice(dst any) { } } -func setEmptyBySlices(rv reflect.Value, rt reflect.Type) { +func SetEmptyBySlices(rv reflect.Value, rt reflect.Type) { if rt.Kind() == reflect.Struct { for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) @@ -71,3 +71,33 @@ func setEmptyBySlices(rv reflect.Value, rt reflect.Type) { } } } + +func SetEmptyByMap(dst any) { + rv := reflect.Indirect(reflect.ValueOf(dst)) + rt := rv.Type() + if rt.Kind() == reflect.Struct { + for i := 0; i < rt.NumField(); i++ { + f := rt.Field(i) + if f.Type.Kind() == reflect.Map && rv.Field(i).Len() == 0 { + mp := reflect.MakeMap(f.Type) + m := reflect.Indirect(mp) + rv.Field(i).Set(m) + continue + } + } + } +} + +func SetEmptyByMaps(rv reflect.Value, rt reflect.Type) { + if rt.Kind() == reflect.Struct { + for i := 0; i < rt.NumField(); i++ { + f := rt.Field(i) + if f.Type.Kind() == reflect.Map && rv.Elem().Field(i).Len() == 0 { + mp := reflect.MakeMap(f.Type) + m := reflect.Indirect(mp) + rv.Elem().Field(i).Set(m) + continue + } + } + } +} diff --git a/cloudfirestore/util_test.go b/cloudfirestore/util_test.go new file mode 100644 index 0000000..d17660e --- /dev/null +++ b/cloudfirestore/util_test.go @@ -0,0 +1,141 @@ +// nolint +package cloudfirestore_test + +import ( + "reflect" + "testing" + + "github.com/rabee-inc/go-pkg/cloudfirestore" +) + +func Test_SetEmptyByMap(t *testing.T) { + type source struct { + Str string + Map map[string]*struct{} + } + + type args struct { + source *source + } + type want struct { + isNil bool + } + type testCase struct { + name string + args args + want want + } + + testCases := []testCase{ + { + name: "補完される", + args: args{ + source: &source{ + Str: "test", + Map: nil, + }, + }, + want: want{ + isNil: false, + }, + }, + { + name: "変化なし", + args: args{ + source: &source{ + Str: "test", + Map: map[string]*struct{}{}, + }, + }, + want: want{ + isNil: false, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + cloudfirestore.SetEmptyByMap(testCase.args.source) + if testCase.args.source.Map == nil { + if !testCase.want.isNil { + t.Errorf("testCase.args.source.Map is nil") + } + } else { + if testCase.want.isNil { + t.Errorf("testCase.args.source.Map is not nil") + } + } + }) + } +} + +func Test_SetEmptyByMaps(t *testing.T) { + type source struct { + Str string + Map map[string]*struct{} + } + + type args struct { + sources []*source + } + type want struct { + isNil bool + } + type testCase struct { + name string + args args + want want + } + + testCases := []testCase{ + { + name: "補完される", + args: args{ + sources: []*source{ + { + Str: "test", + Map: nil, + }, + }, + }, + want: want{ + isNil: false, + }, + }, + { + name: "変化なし", + args: args{ + sources: []*source{ + { + Str: "test", + Map: map[string]*struct{}{}, + }, + }, + }, + want: want{ + isNil: false, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + dsts := []*source{} + rv := reflect.Indirect(reflect.ValueOf(dsts)) + rrt := rv.Type().Elem().Elem() + for _, source := range testCase.args.sources { + rrv := reflect.ValueOf(source) + cloudfirestore.SetEmptyByMaps(rrv, rrt) + if source.Map == nil { + if !testCase.want.isNil { + t.Errorf("source.Map is nil") + } + } else { + if testCase.want.isNil { + t.Errorf("source.Map is not nil") + } + } + } + }) + } +}