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