github.com/altipla-consulting/ravendb-go-client@v0.1.3/hash_calculator.go (about) 1 package ravendb 2 3 import ( 4 "bytes" 5 "crypto/md5" 6 "encoding/binary" 7 "fmt" 8 "io" 9 "reflect" 10 "sort" 11 "time" 12 ) 13 14 type HashCalculator struct { 15 _buffer bytes.Buffer 16 } 17 18 func (h *HashCalculator) getHash() string { 19 data := h._buffer.Bytes() 20 return fmt.Sprintf("%x", md5.Sum(data)) 21 } 22 23 func (h *HashCalculator) write(v interface{}) { 24 if v == nil { 25 io.WriteString(&h._buffer, "null") 26 return 27 } 28 switch v2 := v.(type) { 29 case string: 30 io.WriteString(&h._buffer, v2) 31 case []string: 32 if len(v2) == 0 { 33 io.WriteString(&h._buffer, "null-list-str") 34 return 35 } 36 must(binary.Write(&h._buffer, binary.LittleEndian, int64(len(v2)))) 37 for _, s := range v2 { 38 io.WriteString(&h._buffer, s) 39 } 40 case []interface{}: 41 for _, v := range v2 { 42 h.write(v) 43 } 44 case map[string]string: 45 if len(v2) == 0 { 46 io.WriteString(&h._buffer, "null-dic<string,string>") 47 return 48 } 49 must(binary.Write(&h._buffer, binary.LittleEndian, int64(len(v2)))) 50 // in Go iteration over map is not stable, so need to manually sort keys 51 var keys []string 52 for k := range v2 { 53 keys = append(keys, k) 54 } 55 sort.Strings(keys) 56 for _, k := range keys { 57 v := v2[k] 58 io.WriteString(&h._buffer, k) 59 io.WriteString(&h._buffer, v) 60 } 61 case map[string]interface{}: 62 // this is Parameters 63 if len(v2) == 0 { 64 io.WriteString(&h._buffer, "null-dic<string,object>") 65 return 66 } 67 must(binary.Write(&h._buffer, binary.LittleEndian, int64(len(v2)))) 68 // in Go iteration over map is not stable, so need to manually sort keys 69 var keys []string 70 for k := range v2 { 71 keys = append(keys, k) 72 } 73 sort.Strings(keys) 74 for _, k := range keys { 75 v = v2[k] 76 io.WriteString(&h._buffer, k) 77 if v == nil { 78 io.WriteString(&h._buffer, "null") 79 continue 80 } 81 tp := reflect.TypeOf(v) 82 if _, ok := isPtrStruct(tp); ok || tp.Kind() == reflect.Struct { 83 // when value of parameter is a struct or pointer to struct 84 // it could be our param like SuggestionOptions or 85 // param that is custom type used by the user 86 s := fmt.Sprintf("%#v", v) 87 io.WriteString(&h._buffer, s) 88 continue 89 } 90 h.write(v) 91 } 92 case bool: 93 var toWrite int32 = 1 94 if v2 { 95 toWrite = 2 96 } 97 must(binary.Write(&h._buffer, binary.LittleEndian, toWrite)) 98 case time.Time: 99 t := v2.UTC().Unix() 100 must(binary.Write(&h._buffer, binary.LittleEndian, t)) 101 case int: 102 must(binary.Write(&h._buffer, binary.LittleEndian, int64(v2))) 103 default: 104 //fmt.Printf("Writing value '%v' of type %T\n", v, v) 105 // binary.Write handles all primitive types, except string and int 106 must(binary.Write(&h._buffer, binary.LittleEndian, v)) 107 } 108 }