/
field.go
161 lines (137 loc) · 2.9 KB
/
field.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package struct_filter
import (
"fmt"
"reflect"
"strings"
"github.com/go-pg/pg/internal"
"github.com/go-pg/pg/internal/iszero"
"github.com/go-pg/pg/internal/tag"
"github.com/go-pg/pg/types"
)
type opCode int
const (
opCodeEq opCode = iota + 1
opCodeNotEq
opCodeLT
opCodeLTE
opCodeGT
opCodeGTE
opCodeIEq
opCodeMatch
)
var (
opEq = " = "
opNotEq = " != "
opLT = " < "
opLTE = " <= "
opGT = " > "
opGTE = " >= "
opAny = " = ANY"
opAll = " != ALL"
opIEq = " ILIKE "
opMatch = " SIMILAR TO "
)
type Field struct {
name string
index []int
Column string
opCode opCode
OpValue string
IsSlice bool
noDecode bool
required bool
noWhere bool
Scan ScanFunc
Append types.AppenderFunc
isZero iszero.Func
}
func newField(sf reflect.StructField) *Field {
f := &Field{
name: sf.Name,
index: sf.Index,
IsSlice: sf.Type.Kind() == reflect.Slice,
}
pgTag := tag.Parse(sf.Tag.Get("pg"))
if pgTag.Name == "-" {
return nil
}
if pgTag.Name != "" {
f.name = pgTag.Name
}
_, f.required = pgTag.Options["required"]
_, f.noDecode = pgTag.Options["nodecode"]
_, f.noWhere = pgTag.Options["nowhere"]
if f.required && f.noWhere {
err := fmt.Errorf("required and nowhere tags can't be set together")
panic(err)
}
if f.IsSlice {
f.Column, f.opCode, f.OpValue = splitSliceColumnOperator(f.name)
f.Scan = arrayScanner(sf.Type)
f.Append = types.ArrayAppender(sf.Type)
} else {
f.Column, f.opCode, f.OpValue = splitColumnOperator(f.name, "_")
f.Scan = scanner(sf.Type)
f.Append = types.Appender(sf.Type)
}
f.isZero = iszero.Checker(sf.Type)
if f.Scan == nil || f.Append == nil {
return nil
}
return f
}
func (f *Field) NoDecode() bool {
return f.noDecode
}
func (f *Field) Value(strct reflect.Value) reflect.Value {
return strct.FieldByIndex(f.index)
}
func (f *Field) Omit(value reflect.Value) bool {
return !f.required && f.noWhere || f.isZero(value)
}
func splitColumnOperator(s, sep string) (string, opCode, string) {
s = internal.Underscore(s)
ind := strings.LastIndex(s, sep)
if ind == -1 {
return s, opCodeEq, opEq
}
col := s[:ind]
op := s[ind+len(sep):]
switch op {
case "eq", "":
return col, opCodeEq, opEq
case "neq", "exclude":
return col, opCodeNotEq, opNotEq
case "gt":
return col, opCodeGT, opGT
case "gte":
return col, opCodeGTE, opGTE
case "lt":
return col, opCodeLT, opLT
case "lte":
return col, opCodeLTE, opLTE
case "ieq":
return col, opCodeIEq, opIEq
case "match":
return col, opCodeMatch, opMatch
default:
return s, opCodeEq, opEq
}
}
func splitSliceColumnOperator(s string) (string, opCode, string) {
s = internal.Underscore(s)
ind := strings.LastIndexByte(s, '_')
if ind == -1 {
return s, opCodeEq, opAny
}
col := s[:ind]
op := s[ind+1:]
switch op {
case "eq", "":
return col, opCodeEq, opAny
case "neq", "exclude":
return col, opCodeNotEq, opAll
default:
return s, opCodeEq, opAny
}
}