Skip to content

Instantly share code, notes, and snippets.

@gadelkareem
Created March 9, 2018 06:37
Show Gist options
  • Save gadelkareem/6e42bbb547dc7afd3c119a612fa5a1c5 to your computer and use it in GitHub Desktop.
Save gadelkareem/6e42bbb547dc7afd3c119a612fa5a1c5 to your computer and use it in GitHub Desktop.
Hash model values to enable partial update for the ORM
package main
import (
"strings"
"reflect"
"github.com/mitchellh/hashstructure"
"fmt"
)
type Hash struct {
hashes map[string]uint64
}
func InitHash(in interface{}) *Hash {
h := &Hash{hashes: make(map[string]uint64)}
v := reflect.ValueOf(in).Elem()
var (
name string
hash uint64
skip bool
)
h.hashes = make(map[string]uint64)
for i := 0; i < v.NumField(); i++ {
hash, skip = h.hash(v, i)
if skip {
continue
}
name = h.name(v, i)
if name != "" {
h.hashes[name] = hash
}
}
return h
}
func (h *Hash) hash(v reflect.Value, i int) (uint64, bool) {
if !v.Field(i).CanInterface() {
return 0, true
}
hash, err := hashstructure.Hash(v.Field(i).Interface(), nil)
if err != nil {
fmt.Printf("Error hashing: %v", err)
return 0, true
}
return hash, false
}
func (h *Hash) name(v reflect.Value, i int) string {
spl := strings.Split(v.Type().Field(i).Tag.Get("sql"), ",")
if len(spl) == 0 || spl[0] == "-" {
return ""
}
return spl[0]
}
func (h *Hash) DirtyOnes(in interface{}) []string {
if len(h.hashes) == 0 {
return nil
}
var (
name string
hash, oldHash uint64
exists, skip bool
dirtyOnes []string
)
v := reflect.ValueOf(in).Elem()
for i := 0; i < v.NumField(); i++ {
name = h.name(v, i)
if oldHash, exists = h.hashes[name]; !exists {
continue
}
hash, skip = h.hash(v, i)
if skip {
continue
}
if oldHash != hash {
dirtyOnes = append(dirtyOnes, name)
}
}
return dirtyOnes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment