forked from elgris/sqrl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
array.go
120 lines (99 loc) · 2.65 KB
/
array.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
109
110
111
112
113
114
115
116
117
118
119
120
package pg
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/elgris/sqrl"
)
// Array converts value into Postgres Array
//
// Valid values are slices or arrays of arbitrary depth
// with elements of type string, int, uint and float elements of any bit size
// Example: []int, [][]uint16, [2][2]int, []string
func Array(arr interface{}) sqrl.Sqlizer {
return array{arr}
}
// ToSql builds the query into a SQL string and bound args.
func (a array) ToSql() (string, []interface{}, error) {
if err := checkArrayType(a.value); err != nil {
return "", nil, err
}
buf := &bytes.Buffer{}
marshalArray(reflect.ValueOf(a.value), buf)
return "?", []interface{}{buf.String()}, nil
}
type marshaler func(reflect.Value, *bytes.Buffer)
var marshalers = map[reflect.Kind]marshaler{
reflect.Uint: marshalUint,
reflect.Uint8: marshalUint,
reflect.Uint16: marshalUint,
reflect.Uint32: marshalUint,
reflect.Uint64: marshalUint,
reflect.Int: marshalInt,
reflect.Int8: marshalInt,
reflect.Int16: marshalInt,
reflect.Int32: marshalInt,
reflect.Int64: marshalInt,
reflect.Float32: marshalFloat,
reflect.Float64: marshalFloat,
reflect.String: marshalString,
}
var validElems = makeValidElems(marshalers)
type array struct {
value interface{}
}
func checkArrayType(src interface{}) error {
t := reflect.TypeOf(src)
k := t.Kind()
if k != reflect.Slice && k != reflect.Array {
return fmt.Errorf("Expected value of type slice or array, got %s", k)
}
for k == reflect.Slice || k == reflect.Array {
t = t.Elem()
k = t.Kind()
}
if _, ok := marshalers[k]; !ok {
return fmt.Errorf("Expected element of type %s, got: %s", validElems, k)
}
return nil
}
func marshalArray(v reflect.Value, buf *bytes.Buffer) {
l := v.Len()
if l == 0 {
buf.WriteString("{}")
return
}
k := v.Type().Elem().Kind()
marshalElem, ok := marshalers[k]
if !ok {
marshalElem = marshalArray
}
buf.WriteRune('{')
marshalElem(v.Index(0), buf)
for i := 1; i < v.Len(); i++ {
buf.WriteRune(',')
marshalElem(v.Index(i), buf)
}
buf.WriteRune('}')
}
func marshalInt(v reflect.Value, buf *bytes.Buffer) {
buf.WriteString(strconv.FormatInt(v.Int(), 10))
}
func marshalUint(v reflect.Value, buf *bytes.Buffer) {
buf.WriteString(strconv.FormatUint(v.Uint(), 10))
}
func marshalFloat(v reflect.Value, buf *bytes.Buffer) {
buf.WriteString(strconv.FormatFloat(v.Float(), 'f', -1, 64))
}
func marshalString(v reflect.Value, buf *bytes.Buffer) {
buf.WriteString(strconv.Quote(v.String()))
}
func makeValidElems(m map[reflect.Kind]marshaler) string {
s := make([]string, 0, len(m))
for k := range m {
s = append(s, k.String())
}
return strings.Join(s, ", ")
}