forked from asdine/storm
/
update.go
117 lines (100 loc) · 2.51 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
107
108
109
110
111
112
113
114
115
116
117
package storm
import "reflect"
// Update a structure
func (n *node) Update(data interface{}) error {
return n.update(data, func(ref *reflect.Value, current *reflect.Value, info *modelInfo) error {
numfield := ref.NumField()
for i := 0; i < numfield; i++ {
f := ref.Field(i)
if ref.Type().Field(i).PkgPath != "" {
continue
}
zero := reflect.Zero(f.Type()).Interface()
actual := f.Interface()
if !reflect.DeepEqual(actual, zero) {
cf := current.Field(i)
cf.Set(f)
idxInfo, ok := info.Indexes[ref.Type().Field(i).Name]
if ok {
idxInfo.Value = &cf
}
}
}
return nil
})
}
// UpdateField updates a single field
func (n *node) UpdateField(data interface{}, fieldName string, value interface{}) error {
return n.update(data, func(ref *reflect.Value, current *reflect.Value, info *modelInfo) error {
f := current.FieldByName(fieldName)
if !f.IsValid() {
return ErrNotFound
}
tf, _ := current.Type().FieldByName(fieldName)
if tf.PkgPath != "" {
return ErrNotFound
}
v := reflect.ValueOf(value)
if v.Kind() != f.Kind() {
return ErrIncompatibleValue
}
f.Set(v)
idxInfo, ok := info.Indexes[fieldName]
if ok {
idxInfo.Value = &f
idxInfo.IsZero = idxInfo.isZero()
}
return nil
})
}
func (n *node) update(data interface{}, fn func(*reflect.Value, *reflect.Value, *modelInfo) error) error {
ref := reflect.ValueOf(data)
if !ref.IsValid() || ref.Kind() != reflect.Ptr || ref.Elem().Kind() != reflect.Struct {
return ErrStructPtrNeeded
}
info, err := extract(&ref)
if err != nil {
return err
}
if info.ID.IsZero {
return ErrNoID
}
id, err := toBytes(info.ID.Value.Interface(), n.s.codec)
if err != nil {
return err
}
current := reflect.New(reflect.Indirect(ref).Type())
tx, err := n.Begin(true)
if err != nil {
return err
}
defer tx.Rollback()
ntx := tx.(*node)
err = ntx.One(info.ID.FieldName, info.ID.Value.Interface(), current.Interface())
if err != nil {
return err
}
ref = ref.Elem()
cref := current.Elem()
err = fn(&ref, &cref, info)
if err != nil {
return err
}
raw, err := ntx.s.codec.Marshal(current.Interface())
if err != nil {
return err
}
err = ntx.save(ntx.tx, info, id, raw, nil)
if err != nil {
return err
}
return ntx.Commit()
}
// Update a structure
func (s *DB) Update(data interface{}) error {
return s.root.Update(data)
}
// UpdateField updates a single field
func (s *DB) UpdateField(data interface{}, fieldName string, value interface{}) error {
return s.root.UpdateField(data, fieldName, value)
}