...
1 package hstore
2
3 import (
4 "database/sql"
5 "database/sql/driver"
6 "strings"
7 )
8
9
10 type Hstore struct {
11 Map map[string]sql.NullString
12 }
13
14
15
16 func hQuote(s interface{}) string {
17 var str string
18 switch v := s.(type) {
19 case sql.NullString:
20 if !v.Valid {
21 return "NULL"
22 }
23 str = v.String
24 case string:
25 str = v
26 default:
27 panic("not a string or sql.NullString")
28 }
29
30 str = strings.Replace(str, "\\", "\\\\", -1)
31 return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"`
32 }
33
34
35
36
37
38 func (h *Hstore) Scan(value interface{}) error {
39 if value == nil {
40 h.Map = nil
41 return nil
42 }
43 h.Map = make(map[string]sql.NullString)
44 var b byte
45 pair := [][]byte{{}, {}}
46 pi := 0
47 inQuote := false
48 didQuote := false
49 sawSlash := false
50 bindex := 0
51 for bindex, b = range value.([]byte) {
52 if sawSlash {
53 pair[pi] = append(pair[pi], b)
54 sawSlash = false
55 continue
56 }
57
58 switch b {
59 case '\\':
60 sawSlash = true
61 continue
62 case '"':
63 inQuote = !inQuote
64 if !didQuote {
65 didQuote = true
66 }
67 continue
68 default:
69 if !inQuote {
70 switch b {
71 case ' ', '\t', '\n', '\r':
72 continue
73 case '=':
74 continue
75 case '>':
76 pi = 1
77 didQuote = false
78 continue
79 case ',':
80 s := string(pair[1])
81 if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" {
82 h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false}
83 } else {
84 h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true}
85 }
86 pair[0] = []byte{}
87 pair[1] = []byte{}
88 pi = 0
89 continue
90 }
91 }
92 }
93 pair[pi] = append(pair[pi], b)
94 }
95 if bindex > 0 {
96 s := string(pair[1])
97 if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" {
98 h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false}
99 } else {
100 h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true}
101 }
102 }
103 return nil
104 }
105
106
107
108 func (h Hstore) Value() (driver.Value, error) {
109 if h.Map == nil {
110 return nil, nil
111 }
112 parts := []string{}
113 for key, val := range h.Map {
114 thispart := hQuote(key) + "=>" + hQuote(val)
115 parts = append(parts, thispart)
116 }
117 return []byte(strings.Join(parts, ",")), nil
118 }
119
View as plain text