/
ops.go
129 lines (111 loc) · 3.2 KB
/
ops.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
package aedatastore
import (
"context"
"errors"
"reflect"
w "go.mercari.io/datastore"
"google.golang.org/appengine"
"google.golang.org/appengine/datastore"
)
type getOps func(keys []*datastore.Key, dst []datastore.PropertyList) error
type putOps func(keys []*datastore.Key, src []datastore.PropertyList) ([]w.Key, []w.PendingKey, error)
type deleteOps func(keys []*datastore.Key) error
func getMultiOps(ctx context.Context, keys []w.Key, dst interface{}, ops getOps) error {
v := reflect.ValueOf(dst)
if v.Kind() != reflect.Slice {
return errors.New("datastore: dst has invalid type")
}
if len(keys) != v.Len() {
return errors.New("datastore: keys and dst slices have different length")
}
if len(keys) == 0 {
return nil
}
origKeys := toOriginalKeys(keys)
origPss := make([]datastore.PropertyList, len(keys))
err := ops(origKeys, origPss)
foundError := false
var merr []error
origMerr, catchMerr := err.(appengine.MultiError)
if catchMerr || err == nil {
merr = make([]error, len(keys))
} else if err != nil {
return toWrapperError(err)
}
elemType := v.Type().Elem()
for idx := range keys {
if catchMerr {
err := origMerr[idx]
if _, ok := err.(*datastore.ErrFieldMismatch); ok {
merr[idx] = toWrapperError(err)
foundError = true
} else if err != nil {
merr[idx] = toWrapperError(err)
foundError = true
continue
}
}
ps := toWrapperPropertyList(ctx, origPss[idx])
elem := v.Index(idx)
if reflect.PtrTo(elemType).Implements(typeOfPropertyLoadSaver) {
elem = elem.Addr()
} else if elemType.Kind() == reflect.Struct {
elem = elem.Addr()
} else if elemType.Kind() == reflect.Ptr && elemType.Elem().Kind() == reflect.Struct {
if elem.IsNil() {
elem.Set(reflect.New(elem.Type().Elem()))
}
}
if err = w.LoadEntity(ctx, elem.Interface(), &w.Entity{Key: keys[idx], Properties: ps}); err != nil {
merr[idx] = err
foundError = true
}
}
if foundError {
return w.MultiError(merr)
}
return nil
}
func putMultiOps(ctx context.Context, keys []w.Key, src interface{}, ops putOps) ([]w.Key, []w.PendingKey, error) {
v := reflect.ValueOf(src)
if v.Kind() != reflect.Slice {
return nil, nil, errors.New("datastore: src has invalid type")
}
if len(keys) != v.Len() {
return nil, nil, errors.New("datastore: key and src slices have different length")
}
if len(keys) == 0 {
return nil, nil, nil
}
var origPss []datastore.PropertyList
for idx, key := range keys {
elem := v.Index(idx)
if reflect.PtrTo(elem.Type()).Implements(typeOfPropertyLoadSaver) || elem.Type().Kind() == reflect.Struct {
elem = elem.Addr()
}
src := elem.Interface()
e, err := w.SaveEntity(ctx, key, src)
if err != nil {
return nil, nil, toWrapperError(err)
}
origPs, err := toOriginalPropertyList(e.Properties)
if err != nil {
return nil, nil, err
}
origPss = append(origPss, origPs)
}
origKeys := toOriginalKeys(keys)
wKeys, wPKeys, err := ops(origKeys, origPss)
if err != nil {
return nil, nil, toWrapperError(err)
}
return wKeys, wPKeys, nil
}
func deleteMultiOps(ctx context.Context, keys []w.Key, ops deleteOps) error {
origKeys := toOriginalKeys(keys)
err := ops(origKeys)
if err != nil {
return toWrapperError(err)
}
return nil
}