Created
August 19, 2021 06:02
-
-
Save Yama-Tomo/435b0b637075d776cc18726e9ea13567 to your computer and use it in GitHub Desktop.
transform struct to map for firestore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"cloud.google.com/go/firestore" | |
"time" | |
"fmt" | |
"reflect" | |
"strings" | |
) | |
type Struct struct { | |
DocID string `firestore:"-"` | |
Name string `firestore:"name"` | |
Time time.Time `firestore:"time"` | |
Tags []string `firestore:"tags"` | |
NestedData1 *NestedStruct `firestore:"nested_data_1" nested:"true"` | |
NestedData2 NestedStruct `firestore:"nested_data_2" nested:"true"` | |
NestedDataItems []NestedStruct `firestore:"nested_data_items" nested:"true"` | |
UpdatedAt *time.Time `firestore:"updated_at, serverTimestamp"` | |
CreatedAt *time.Time `firestore:"created_at,serverTimestamp"` | |
} | |
type NestedStruct struct { | |
Label string `firestore:"label"` | |
Count int `firestore:"count"` | |
UpdatedAt *time.Time `firestore:"updated_at,serverTimestamp"` | |
CreatedAt *time.Time `firestore:"created_at,serverTimestamp"` | |
} | |
func main() { | |
nested1 := &NestedStruct{ | |
Label: "test", | |
Count: 1, | |
} | |
now := time.Now() | |
nested2 := NestedStruct{ | |
Label: "test", | |
Count: 2, | |
CreatedAt: &now, | |
} | |
strct := Struct{ | |
DocID: "xxxxx-yyyyyy-zzzzz", | |
Name: "hoge", | |
Tags: []string{"foo", "bar"}, | |
NestedDataItems: []NestedStruct{nested2}, | |
Time: time.Now(), | |
NestedData1: nested1, | |
NestedData2: nested2, | |
} | |
fmt.Println(TransformStructToMap(strct)) | |
} | |
func TransformStructToMap(structVal interface{}) map[string]interface{} { | |
result := map[string]interface{}{} | |
structRef := reflect.Indirect(reflect.ValueOf(structVal)) | |
if structRef.Kind() != reflect.Struct { | |
return result | |
} | |
for i := 0; i < structRef.NumField(); i++ { | |
fieldName, meta := getFieldNameAndMeta(structRef.Type().Field(i)) | |
if fieldName == "" || fieldName == "-" { | |
continue | |
} | |
if strings.Contains(meta, "serverTimestamp") { | |
result[fieldName] = firestore.ServerTimestamp | |
continue | |
} | |
fieldRef := structRef.Field(i) | |
if structRef.Type().Field(i).Tag.Get("nested") == "true" { | |
var nestedVal interface{} | |
if fieldRef.Kind() == reflect.Slice { | |
var slice []interface{} | |
for sliceIdx := 0; i < structRef.Field(sliceIdx).Len(); sliceIdx++ { | |
slice = append(slice, TransformStructToMap(fieldRef.Index(sliceIdx).Interface())) | |
} | |
nestedVal = slice | |
} else { | |
nestedVal = TransformStructToMap(fieldRef.Interface()) | |
} | |
result[fieldName] = nestedVal | |
continue | |
} | |
result[fieldName] = fieldRef.Interface() | |
} | |
return result | |
} | |
func getFieldNameAndMeta(field reflect.StructField) (string, string) { | |
targets := []string{ | |
field.Tag.Get("firestore"), | |
field.Tag.Get("json"), | |
field.Name, | |
} | |
for _, target := range targets { | |
if target == "" { | |
continue | |
} | |
if strings.Contains(target, ",") { | |
arr := strings.SplitN(target, ",", 2) | |
return arr[0], arr[1] | |
} | |
return target, "" | |
} | |
return "", "" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment