go.mercari.io/datastore@v1.8.2/boom/tx_aecompat.go (about) 1 package boom 2 3 import ( 4 "reflect" 5 6 "go.mercari.io/datastore" 7 ) 8 9 // IMPORTANT NOTICE: You should use *boom.Transaction. 10 11 var _ AECompatibleOperations = &Boom{} 12 var _ AECompatibleOperations = &AECompatibleTransaction{} 13 14 // AECompatibleOperations represents Transaction, if not, both common operations. 15 // In AppEngine Datastore transactions immediately return Key. 16 // In order to realize this, this wrapper internally performs AllocateID when it is required. 17 // 18 // This is for migrating existing code and should not be used if possible. 19 type AECompatibleOperations interface { 20 Kind(src interface{}) string 21 Key(src interface{}) datastore.Key 22 KeyError(src interface{}) (datastore.Key, error) 23 Get(dst interface{}) error 24 GetMulti(dst interface{}) error 25 Put(src interface{}) (datastore.Key, error) 26 PutMulti(src interface{}) ([]datastore.Key, error) 27 Delete(src interface{}) error 28 DeleteMulti(src interface{}) error 29 } 30 31 // ToAECompatibleTransaction converts a transaction to AECompatibleTransaction. 32 // AECompatibleTransaction implements AECompatibleOperations. 33 func ToAECompatibleTransaction(tx *Transaction) *AECompatibleTransaction { 34 return &AECompatibleTransaction{bm: tx.bm, tx: tx.tx} 35 } 36 37 // AECompatibleTransaction implements AECompatibleOperations. 38 // It is useful for migration when using AppEngine Datastore, 39 // when using transactions or not using it with using the same code. 40 type AECompatibleTransaction struct { 41 bm *Boom 42 tx datastore.Transaction 43 } 44 45 // Boom object that is the source of the Batch object is returned. 46 func (tx *AECompatibleTransaction) Boom() *Boom { 47 return tx.bm 48 } 49 50 // Kind retrieves kind name from struct. 51 func (tx *AECompatibleTransaction) Kind(src interface{}) string { 52 return tx.bm.Kind(src) 53 } 54 55 // Key retrieves datastore key from struct without error occurred. 56 func (tx *AECompatibleTransaction) Key(src interface{}) datastore.Key { 57 return tx.bm.Key(src) 58 } 59 60 // KeyError retrieves datastore key from struct with error occurred. 61 func (tx *AECompatibleTransaction) KeyError(src interface{}) (datastore.Key, error) { 62 return tx.bm.KeyError(src) 63 } 64 65 // Get loads the entity stored for key into dst, which must be a struct pointer or implement PropertyLoadSaver. 66 // key will be extracted from dst. 67 // 68 // If there is no such entity for the key, Get returns ErrNoSuchEntity. 69 // The values of dst's unmatched struct fields are not modified, and matching slice-typed fields are not reset before appending to them. 70 // In particular, it is recommended to pass a pointer to a zero valued struct on each Get call. 71 func (tx *AECompatibleTransaction) Get(dst interface{}) error { 72 dsts := []interface{}{dst} 73 err := tx.GetMulti(dsts) 74 if merr, ok := err.(datastore.MultiError); ok { 75 return merr[0] 76 } else if err != nil { 77 return err 78 } 79 80 return nil 81 } 82 83 // GetMulti is a batch version of Get. 84 // key will be extracted from each struct of dst. 85 // 86 // dst must be a []S, []*S, []I or []P, for some struct type S, some interface type I, or some non-interface non-pointer type P such that P or *P implements PropertyLoadSaver. 87 // If an []I, each element must be a valid dst for Get: it must be a struct pointer or implement PropertyLoadSaver. 88 func (tx *AECompatibleTransaction) GetMulti(dst interface{}) error { 89 keys, err := tx.bm.extractKeys(dst) 90 if err != nil { 91 return err 92 } 93 94 return tx.tx.GetMulti(keys, dst) 95 } 96 97 // Put saves the entity src into the datastore. 98 // key will be extract from src struct. 99 // src must be a struct pointer or implement PropertyLoadSaver; if a struct pointer then any unexported fields of that struct will be skipped. 100 // If k is an incomplete key, the returned key will be a unique key generated by the datastore, 101 // and inject key to src struct. 102 func (tx *AECompatibleTransaction) Put(src interface{}) (datastore.Key, error) { 103 srcs := []interface{}{src} 104 keys, err := tx.PutMulti(srcs) 105 if merr, ok := err.(datastore.MultiError); ok { 106 return nil, merr[0] 107 } else if err != nil { 108 return nil, err 109 } 110 111 return keys[0], nil 112 } 113 114 // PutMulti is a batch version of Put. 115 // 116 // src must satisfy the same conditions as the dst argument to GetMulti. 117 func (tx *AECompatibleTransaction) PutMulti(src interface{}) ([]datastore.Key, error) { 118 keys, err := tx.bm.extractKeys(src) 119 if err != nil { 120 return nil, err 121 } 122 123 // This api should returns []datastore.Key. 124 // Use AllocateIDs instead of []datastore.PendingKey. 125 incompleteIndexes := make([]int, 0, len(keys)) 126 incompleteKeys := make([]datastore.Key, 0, len(keys)) 127 for idx, key := range keys { 128 if key.Incomplete() { 129 incompleteIndexes = append(incompleteIndexes, idx) 130 incompleteKeys = append(incompleteKeys, key) 131 } 132 } 133 incompleteKeys, err = tx.bm.AllocateIDs(incompleteKeys) 134 if err != nil { 135 return nil, err 136 } 137 for idx, inIdx := range incompleteIndexes { 138 keys[inIdx] = incompleteKeys[idx] 139 } 140 141 _, err = tx.tx.PutMulti(keys, src) 142 if err != nil { 143 return nil, err 144 } 145 146 v := reflect.Indirect(reflect.ValueOf(src)) 147 for idx, key := range keys { 148 err = tx.bm.setStructKey(v.Index(idx).Interface(), key) 149 if err != nil { 150 return nil, err 151 } 152 } 153 154 return keys, nil 155 } 156 157 // Delete deletes the entity. 158 // key will be extract from src struct. 159 func (tx *AECompatibleTransaction) Delete(src interface{}) error { 160 srcs := []interface{}{src} 161 err := tx.DeleteMulti(srcs) 162 if merr, ok := err.(datastore.MultiError); ok { 163 return merr[0] 164 } else if err != nil { 165 return err 166 } 167 168 return nil 169 } 170 171 // DeleteMulti is a batch version of Delete. 172 func (tx *AECompatibleTransaction) DeleteMulti(src interface{}) error { 173 keys, err := tx.bm.extractKeys(src) 174 if err != nil { 175 return err 176 } 177 178 return tx.tx.DeleteMulti(keys) 179 } 180 181 // Commit applies the enqueued operations atomically. 182 func (tx *AECompatibleTransaction) Commit() (datastore.Commit, error) { 183 commit, err := tx.tx.Commit() 184 if err != nil { 185 return nil, err 186 } 187 188 return commit, nil 189 } 190 191 // Rollback abandons a pending transaction. 192 func (tx *AECompatibleTransaction) Rollback() error { 193 return tx.tx.Rollback() 194 }