-
Notifications
You must be signed in to change notification settings - Fork 6
/
update.go
106 lines (96 loc) · 2.3 KB
/
update.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
package y
import (
"log"
"reflect"
sq "github.com/Masterminds/squirrel"
)
// Modifier changes a value for update statement
type Modifier func(v interface{}) interface{}
// IncrInt returns a modifier for int/int8/int16/int32/int64 increment
func IncrInt(to interface{}) Modifier {
return func(v interface{}) interface{} {
if x, ok := v.(int); ok {
return x + to.(int)
}
if x, ok := v.(int8); ok {
return x + to.(int8)
}
if x, ok := v.(int16); ok {
return x + to.(int16)
}
if x, ok := v.(int32); ok {
return x + to.(int32)
}
if x, ok := v.(int64); ok {
return x + to.(int64)
}
panic("y/update: unknown int type for increment.")
}
}
// IncrFloat returns a modifier for float32/float64 increment
func IncrFloat(to interface{}) Modifier {
return func(v interface{}) interface{} {
if x, ok := v.(float32); ok {
return x + to.(float32)
}
if x, ok := v.(float64); ok {
return x + to.(float64)
}
panic("y/update: unknown float type for increment.")
}
}
// Changer updates object values
type Changer struct {
proxy *Proxy
values Values
}
func (c *Changer) modify() sq.Eq {
modified := sq.Eq{}
delete(c.values, _version)
for name, val := range c.values {
f := c.proxy.Field(name)
if modifier, ok := val.(Modifier); ok {
val = modifier(f.Interface())
}
if f.Interface() != val {
modified[name] = val
f.Set(reflect.ValueOf(val))
}
}
return modified
}
// Update saves object changes in db after version validation
func (c *Changer) Update(db sq.BaseRunner) (err error) {
version := c.proxy.version()
if !version.Valid {
log.Panicf(
"y/update: You must load \"%s\" before update it", c.proxy.schema.table)
}
pk := c.proxy.primary()
// add old version to search condition
pk[_version] = version.Int64
// find changes
clauses := c.modify()
if len(clauses) == 0 {
return
}
// set new version
version.Int64++
clauses[_version] = version.Int64
// save
result, err := builder{c.proxy.schema}.forUpdate(clauses, sq.Eq(pk)).RunWith(db).Exec()
if err == nil {
count, _ := result.RowsAffected()
if count != 1 {
err = ErrNoAffectedRows
}
}
return
}
func makeChanger(p *Proxy, v Values) *Changer {
return &Changer{p, v}
}
// Update saves object changes
func Update(db sq.BaseRunner, p *Proxy, v Values) error {
return makeChanger(p, v).Update(db)
}