浏览代码

clientv3: optionize put and delete

Anthony Romano 10 年之前
父节点
当前提交
3c9e8540a7

+ 8 - 8
clientv3/integration/kv_test.go

@@ -55,7 +55,7 @@ func TestKVPut(t *testing.T) {
 	}
 
 	for i, tt := range tests {
-		if _, err := kv.Put(ctx, tt.key, tt.val, tt.leaseID); err != nil {
+		if _, err := kv.Put(ctx, tt.key, tt.val, clientv3.WithLease(tt.leaseID)); err != nil {
 			t.Fatalf("#%d: couldn't put %q (%v)", i, tt.key, err)
 		}
 		resp, err := kv.Get(ctx, tt.key)
@@ -85,7 +85,7 @@ func TestKVRange(t *testing.T) {
 
 	keySet := []string{"a", "b", "c", "c", "c", "foo", "foo/abc", "fop"}
 	for i, key := range keySet {
-		if _, err := kv.Put(ctx, key, "", lease.NoLease); err != nil {
+		if _, err := kv.Put(ctx, key, ""); err != nil {
 			t.Fatalf("#%d: couldn't put %q (%v)", i, key, err)
 		}
 	}
@@ -199,7 +199,7 @@ func TestKVDeleteRange(t *testing.T) {
 
 	keySet := []string{"a", "b", "c", "c", "c", "d", "e", "f"}
 	for i, key := range keySet {
-		if _, err := kv.Put(ctx, key, "", lease.NoLease); err != nil {
+		if _, err := kv.Put(ctx, key, ""); err != nil {
 			t.Fatalf("#%d: couldn't put %q (%v)", i, key, err)
 		}
 	}
@@ -213,7 +213,7 @@ func TestKVDeleteRange(t *testing.T) {
 	}
 
 	for i, tt := range tests {
-		dresp, err := kv.DeleteRange(ctx, tt.key, tt.end)
+		dresp, err := kv.Delete(ctx, tt.key, clientv3.WithRange(tt.end))
 		if err != nil {
 			t.Fatalf("#%d: couldn't delete range (%v)", i, err)
 		}
@@ -239,7 +239,7 @@ func TestKVDelete(t *testing.T) {
 	kv := clientv3.NewKV(clus.RandClient())
 	ctx := context.TODO()
 
-	presp, err := kv.Put(ctx, "foo", "", lease.NoLease)
+	presp, err := kv.Put(ctx, "foo", "")
 	if err != nil {
 		t.Fatalf("couldn't put 'foo' (%v)", err)
 	}
@@ -272,7 +272,7 @@ func TestKVCompact(t *testing.T) {
 	ctx := context.TODO()
 
 	for i := 0; i < 10; i++ {
-		if _, err := kv.Put(ctx, "foo", "bar", lease.NoLease); err != nil {
+		if _, err := kv.Put(ctx, "foo", "bar"); err != nil {
 			t.Fatalf("couldn't put 'foo' (%v)", err)
 		}
 	}
@@ -311,7 +311,7 @@ func TestKVGetRetry(t *testing.T) {
 	kv := clientv3.NewKV(clus.Client(0))
 	ctx := context.TODO()
 
-	if _, err := kv.Put(ctx, "foo", "bar", 0); err != nil {
+	if _, err := kv.Put(ctx, "foo", "bar"); err != nil {
 		t.Fatal(err)
 	}
 
@@ -363,7 +363,7 @@ func TestKVPutFailGetRetry(t *testing.T) {
 	clus.Members[0].Stop(t)
 	<-clus.Members[0].StopNotify()
 
-	_, err := kv.Put(ctx, "foo", "bar", 0)
+	_, err := kv.Put(ctx, "foo", "bar")
 	if err == nil {
 		t.Fatalf("got success on disconnected put, wanted error")
 	}

+ 2 - 2
clientv3/integration/lease_test.go

@@ -42,7 +42,7 @@ func TestLeaseCreate(t *testing.T) {
 		t.Errorf("failed to create lease %v", err)
 	}
 
-	_, err = kv.Put(context.TODO(), "foo", "bar", lease.LeaseID(resp.ID))
+	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
 	if err != nil {
 		t.Fatalf("failed to create key with lease %v", err)
 	}
@@ -69,7 +69,7 @@ func TestLeaseRevoke(t *testing.T) {
 		t.Errorf("failed to revoke lease %v", err)
 	}
 
-	_, err = kv.Put(context.TODO(), "foo", "bar", lease.LeaseID(resp.ID))
+	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
 	if err != v3rpc.ErrLeaseNotFound {
 		t.Fatalf("err = %v, want %v", err, v3rpc.ErrLeaseNotFound)
 	}

+ 2 - 2
clientv3/integration/txn_test.go

@@ -38,7 +38,7 @@ func TestTxnWriteFail(t *testing.T) {
 
 	donec := make(chan struct{})
 	go func() {
-		resp, err := kv.Txn(ctx).Then(clientv3.OpPut("foo", "bar", 0)).Commit()
+		resp, err := kv.Txn(ctx).Then(clientv3.OpPut("foo", "bar")).Commit()
 		if err == nil {
 			t.Fatalf("expected error, got response %v", resp)
 		}
@@ -123,7 +123,7 @@ func TestTxnSuccess(t *testing.T) {
 	kv := clientv3.NewKV(clus.Client(0))
 	ctx := context.TODO()
 
-	_, err := kv.Txn(ctx).Then(clientv3.OpPut("foo", "bar", 0)).Commit()
+	_, err := kv.Txn(ctx).Then(clientv3.OpPut("foo", "bar")).Commit()
 	if err != nil {
 		t.Fatal(err)
 	}

+ 3 - 3
clientv3/integration/watch_test.go

@@ -146,7 +146,7 @@ func testWatchMultiWatcher(t *testing.T, wctx *watchctx) {
 	for i := 0; i < numKeyUpdates; i++ {
 		for _, k := range keys {
 			v := fmt.Sprintf("%s-%d", k, i)
-			if _, err := wctx.kv.Put(ctx, k, v, 0); err != nil {
+			if _, err := wctx.kv.Put(ctx, k, v); err != nil {
 				t.Fatal(err)
 			}
 		}
@@ -221,7 +221,7 @@ func testWatchCancelRunning(t *testing.T, wctx *watchctx) {
 	if wctx.ch = wctx.w.Watch(ctx, "a", 0); wctx.ch == nil {
 		t.Fatalf("expected non-nil watcher channel")
 	}
-	if _, err := wctx.kv.Put(ctx, "a", "a", 0); err != nil {
+	if _, err := wctx.kv.Put(ctx, "a", "a"); err != nil {
 		t.Fatal(err)
 	}
 	cancel()
@@ -246,7 +246,7 @@ func testWatchCancelRunning(t *testing.T, wctx *watchctx) {
 }
 
 func putAndWatch(t *testing.T, wctx *watchctx, key, val string) {
-	if _, err := wctx.kv.Put(context.TODO(), key, val, 0); err != nil {
+	if _, err := wctx.kv.Put(context.TODO(), key, val); err != nil {
 		t.Fatal(err)
 	}
 	select {

+ 11 - 24
clientv3/kv.go

@@ -20,15 +20,13 @@ import (
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
-	"github.com/coreos/etcd/lease"
 )
 
 type (
-	PutResponse         pb.PutResponse
-	GetResponse         pb.RangeResponse
-	DeleteRangeResponse pb.DeleteRangeResponse
-	DeleteResponse      pb.DeleteRangeResponse
-	TxnResponse         pb.TxnResponse
+	PutResponse    pb.PutResponse
+	GetResponse    pb.RangeResponse
+	DeleteResponse pb.DeleteRangeResponse
+	TxnResponse    pb.TxnResponse
 )
 
 type KV interface {
@@ -36,7 +34,7 @@ type KV interface {
 	// Note that key,value can be plain bytes array and string is
 	// an immutable representation of that bytes array.
 	// To get a string of bytes, do string([]byte(0x10, 0x20)).
-	Put(ctx context.Context, key, val string, leaseID lease.LeaseID) (*PutResponse, error)
+	Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error)
 
 	// Get retrieves keys.
 	// By default, Get will return the value for "key", if any.
@@ -47,11 +45,8 @@ type KV interface {
 	// When passed WithSort(), the keys will be sorted.
 	Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error)
 
-	// DeleteRange deletes the given range [key, end).
-	DeleteRange(ctx context.Context, key, end string) (*DeleteRangeResponse, error)
-
-	// Delete is like DeleteRange. A shortcut for deleting single key like [key, key+1).
-	Delete(ctx context.Context, key string) (*DeleteResponse, error)
+	// Delete deletes a key, or optionallly using WithRange(end), [key, end).
+	Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error)
 
 	// Compact compacts etcd KV history before the given rev.
 	Compact(ctx context.Context, rev int64) error
@@ -80,8 +75,8 @@ func NewKV(c *Client) KV {
 	}
 }
 
-func (kv *kv) Put(ctx context.Context, key, val string, leaseID lease.LeaseID) (*PutResponse, error) {
-	r, err := kv.do(ctx, OpPut(key, val, leaseID))
+func (kv *kv) Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) {
+	r, err := kv.do(ctx, OpPut(key, val, opts...))
 	if err != nil {
 		return nil, err
 	}
@@ -96,16 +91,8 @@ func (kv *kv) Get(ctx context.Context, key string, opts ...OpOption) (*GetRespon
 	return (*GetResponse)(r.GetResponseRange()), nil
 }
 
-func (kv *kv) DeleteRange(ctx context.Context, key, end string) (*DeleteRangeResponse, error) {
-	r, err := kv.do(ctx, OpDeleteRange(key, end))
-	if err != nil {
-		return nil, err
-	}
-	return (*DeleteRangeResponse)(r.GetResponseDeleteRange()), nil
-}
-
-func (kv *kv) Delete(ctx context.Context, key string) (*DeleteResponse, error) {
-	r, err := kv.do(ctx, OpDelete(key))
+func (kv *kv) Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) {
+	r, err := kv.do(ctx, OpDelete(key, opts...))
 	if err != nil {
 		return nil, err
 	}

+ 33 - 19
clientv3/op.go

@@ -70,39 +70,53 @@ func (op Op) isWrite() bool {
 
 func OpGet(key string, opts ...OpOption) Op {
 	ret := Op{t: tRange, key: []byte(key)}
-	for _, opt := range opts {
-		opt(&ret)
-	}
+	ret.applyOpts(opts)
 	return ret
 }
 
-func OpDeleteRange(key, end string) Op {
-	return Op{
-		t:   tDeleteRange,
-		key: []byte(key),
-		end: []byte(end),
+func OpDelete(key string, opts ...OpOption) Op {
+	ret := Op{t: tDeleteRange, key: []byte(key)}
+	ret.applyOpts(opts)
+	switch {
+	case ret.leaseID != 0:
+		panic("unexpected lease in delete")
+	case ret.limit != 0:
+		panic("unexpected limit in delete")
+	case ret.rev != 0:
+		panic("unexpected revision in delete")
+	case ret.sort != nil:
+		panic("unexpected sort in delete")
 	}
+	return ret
 }
 
-func OpDelete(key string) Op {
-	return Op{
-		t:   tDeleteRange,
-		key: []byte(key),
+func OpPut(key, val string, opts ...OpOption) Op {
+	ret := Op{t: tPut, key: []byte(key), val: []byte(val)}
+	ret.applyOpts(opts)
+	switch {
+	case ret.end != nil:
+		panic("unexpected range in put")
+	case ret.limit != 0:
+		panic("unexpected limit in put")
+	case ret.rev != 0:
+		panic("unexpected revision in put")
+	case ret.sort != nil:
+		panic("unexpected sort in put")
 	}
+	return ret
 }
 
-func OpPut(key, val string, leaseID lease.LeaseID) Op {
-	return Op{
-		t:   tPut,
-		key: []byte(key),
-
-		val:     []byte(val),
-		leaseID: leaseID,
+func (op *Op) applyOpts(opts []OpOption) {
+	for _, opt := range opts {
+		opt(op)
 	}
 }
 
 type OpOption func(*Op)
 
+func WithLease(leaseID lease.LeaseID) OpOption {
+	return func(op *Op) { op.leaseID = leaseID }
+}
 func WithLimit(n int64) OpOption { return func(op *Op) { op.limit = n } }
 func WithRev(rev int64) OpOption { return func(op *Op) { op.rev = rev } }
 func WithSort(tgt SortTarget, order SortOrder) OpOption {

+ 1 - 1
clientv3/txn_test.go

@@ -34,7 +34,7 @@ func TestTxnPanics(t *testing.T) {
 	}
 
 	cmp := Compare(CreatedRevision("foo"), "=", 0)
-	op := OpPut("foo", "bar", 0)
+	op := OpPut("foo", "bar")
 
 	tests := []struct {
 		f func()