Skip to content

Instantly share code, notes, and snippets.

@iMikio
Forked from roboncode/firestore.go
Last active June 25, 2023 03:01
Show Gist options
  • Save iMikio/5eb2f9652e7965d440ab5a5708fe0d09 to your computer and use it in GitHub Desktop.
Save iMikio/5eb2f9652e7965d440ab5a5708fe0d09 to your computer and use it in GitHub Desktop.
Firestore - GoLang Transform Struct To Map
package transform
import (
"reflect"
"strings"
"time"
)
const (
tagName = "firestore"
tagOmitEmpty = "omitempty"
tagServerTimestamp = "serverTimestamp"
delimiter = ","
)
type FirestoreMap map[string]interface{}
func ToFirestoreMap(value interface{}) FirestoreMap {
var result = parseData(value)
return result.(FirestoreMap)
}
func isZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
func parseData(value interface{}) interface{} {
if value == nil {
return nil
}
var firestoreMap = FirestoreMap{}
var tag string
//var value interface{}
var fieldCount int
var val = reflect.ValueOf(value)
switch value.(type) {
case time.Time, *time.Time:
return value
}
switch val.Kind() {
case reflect.Map:
for _, key := range val.MapKeys() {
val := val.MapIndex(key)
firestoreMap[key.String()] = parseData(val.Interface())
}
return firestoreMap
case reflect.Ptr:
if val.IsNil() {
return nil
}
fieldCount = val.Elem().NumField()
for i := 0; i < fieldCount; i++ {
tag = val.Elem().Type().Field(i).Tag.Get(tagName)
value = val.Elem().Field(i).Interface()
setValue(firestoreMap, tag, value)
}
return firestoreMap
case reflect.Struct, reflect.Interface:
fieldCount = val.NumField()
for i := 0; i < fieldCount; i++ {
tag = val.Type().Field(i).Tag.Get(tagName)
value = val.Field(i).Interface()
setValue(firestoreMap, tag, value)
}
return firestoreMap
}
return value
}
func setValue(firestoreMap FirestoreMap, tag string, value interface{}) {
if tag == "" || tag == "-" || value == nil {
return
}
tagValues := strings.Split(tag, delimiter)
fieldName := tagValues[0]
if strings.Contains(tag, tagOmitEmpty) {
if isZeroOfUnderlyingType(value) {
return
}
}
if strings.Contains(tag, tagServerTimestamp) {
if isZeroOfUnderlyingType(value) {
firestoreMap[fieldName] = firestore.ServerTimestamp
return
}
}
firestoreMap[fieldName] = parseData(value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment