@@ -2,6 +2,8 @@ package e2db
22
33import (
44 "context"
5+ "fmt"
6+ "path/filepath"
57 "reflect"
68 "strings"
79 "time"
@@ -12,6 +14,7 @@ import (
1214 "github.com/pkg/errors"
1315 "go.etcd.io/etcd/clientv3"
1416 "go.etcd.io/etcd/etcdserver/etcdserverpb"
17+ "go.uber.org/zap"
1518)
1619
1720var (
@@ -196,36 +199,102 @@ func (tx *Tx) Update(iface interface{}) error {
196199 return err
197200}
198201
202+ // getIndexesByPrimaryKey returns all index keys for the provided primary key
203+ // based on the stored value.
204+ func (tx * Tx ) getIndexesByPrimaryKey (pk string ) ([]string , error ) {
205+ val := tx .meta .New ()
206+ if val == nil {
207+ return nil , errors .Errorf ("underlying type is uninitialized: %s" , tx .meta .Name )
208+ }
209+ v := reflect .Indirect (reflect .ValueOf (val .Interface ()))
210+ if err := newQuery (tx .Table ).findOneByPrimaryKey (pk , v ); err != nil {
211+ if errors .Cause (err ) == ErrNoRows {
212+ return nil , nil
213+ }
214+ return nil , err
215+ }
216+ keys := []string {pk }
217+ _ , id := filepath .Split (pk )
218+ for n , f := range tx .meta .Fields {
219+ switch f .Type () {
220+ case UniqueIndex :
221+ keys = append (keys , key .Unique (tx .meta .Name , n , toString (v .FieldByName (n ).Interface ())))
222+ case SecondaryIndex :
223+ keys = append (keys , key .Index (tx .meta .Name , n , toString (v .FieldByName (n ).Interface ()), id ))
224+ }
225+ }
226+ return keys , nil
227+ }
228+
229+ func deleteOps (keys []string ) (ops []clientv3.Op ) {
230+ for _ , k := range keys {
231+ ops = append (ops , clientv3 .OpDelete (k ))
232+ }
233+ return
234+ }
235+
199236func (tx * Tx ) Delete (fieldName string , data interface {}) (int64 , error ) {
237+ var n int64
238+ st := time .Now ()
239+ defer func () {
240+ log .Debug ("tx.Delete" ,
241+ zap .String ("key" , fmt .Sprintf ("%s/%v" , tx .meta .Name , fieldName )),
242+ zap .String ("q" , toString (data )),
243+ zap .Int64 ("n" , n ),
244+ zap .Duration ("elapsed" , time .Now ().Sub (st )),
245+ )
246+ }()
200247 f , ok := tx .meta .Fields [fieldName ]
201248 if ! ok {
202249 return 0 , errors .Errorf ("invalid field name: %#v" , fieldName )
203250 }
204251 k := toString (data )
205- if f .isPrimaryKey () {
206- resp , err := tx .db .client .Delete (context .TODO (), key .ID (tx .meta .Name , k ))
252+ pks := make ([]string , 0 )
253+
254+ // get the primary key of the item(s) being deleted
255+ switch f .Type () {
256+ case PrimaryKey :
257+ pks = append (pks , key .ID (tx .meta .Name , k ))
258+ case UniqueIndex :
259+ b , err := tx .db .client .Get (key .Unique (tx .meta .Name , fieldName , k ))
207260 if err != nil {
261+ if errors .Cause (err ) == client .ErrKeyNotFound {
262+ return 0 , nil
263+ }
208264 return 0 , err
209265 }
210- return resp .Deleted , nil
211- }
212- kvs , err := tx .db .client .Prefix (key .Indexes (tx .meta .Name , fieldName , k ))
213- if err != nil {
214- if errors .Cause (err ) == client .ErrKeyNotFound {
215- return 0 , nil
266+ pks = append (pks , string (b ))
267+ case SecondaryIndex :
268+ x := key .Indexes (tx .meta .Name , fieldName , k )
269+ kvs , err := tx .db .client .Prefix (x )
270+ if err != nil {
271+ if errors .Cause (err ) == client .ErrKeyNotFound {
272+ return 0 , nil
273+ }
274+ return 0 , err
216275 }
217- return 0 , err
276+ for _ , kv := range kvs {
277+ pks = append (pks , string (kv .Value ))
278+ }
279+ default :
280+ return 0 , errors .Wrapf (ErrNotIndexed , "cannot delete %#v" , fieldName )
218281 }
282+
219283 ops := make ([]clientv3.Op , 0 )
220- for _ , kv := range kvs {
221- ops = append (ops , clientv3 .OpDelete (string (kv .Key )))
222- ops = append (ops , clientv3 .OpDelete (string (kv .Value )))
284+ for _ , pk := range pks {
285+ keys , err := tx .getIndexesByPrimaryKey (pk )
286+ if err != nil {
287+ return 0 , err
288+ }
289+ if len (keys ) > 0 {
290+ n ++
291+ }
292+ ops = append (ops , deleteOps (keys )... )
223293 }
224- resp , err := tx .batchOps (ops ... )
225- if err != nil {
294+ if _ , err := tx .batchOps (ops ... ); err != nil {
226295 return 0 , err
227296 }
228- return resp . Deleted , nil
297+ return n , nil
229298}
230299
231300func (tx * Tx ) DeleteAll () error {
0 commit comments