diff --git a/clientv3/integration/kv_test.go b/clientv3/integration/kv_test.go index f2b69b238..c6dfab8f2 100644 --- a/clientv3/integration/kv_test.go +++ b/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") } diff --git a/clientv3/integration/lease_test.go b/clientv3/integration/lease_test.go index fdbdfe470..cc1a770c9 100644 --- a/clientv3/integration/lease_test.go +++ b/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) } diff --git a/clientv3/integration/txn_test.go b/clientv3/integration/txn_test.go index 6cf0f8e48..329f8419b 100644 --- a/clientv3/integration/txn_test.go +++ b/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) } diff --git a/clientv3/integration/watch_test.go b/clientv3/integration/watch_test.go index e343214b0..2e13ab9e9 100644 --- a/clientv3/integration/watch_test.go +++ b/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 { diff --git a/clientv3/kv.go b/clientv3/kv.go index aa60a4209..6f9a81532 100644 --- a/clientv3/kv.go +++ b/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 } diff --git a/clientv3/op.go b/clientv3/op.go index 532cd87c7..e7c499090 100644 --- a/clientv3/op.go +++ b/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 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 OpDeleteRange(key, end string) Op { - return Op{ - t: tDeleteRange, - key: []byte(key), - end: []byte(end), +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 OpDelete(key string) Op { - return Op{ - t: tDeleteRange, - key: []byte(key), - } -} - -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 { diff --git a/clientv3/txn_test.go b/clientv3/txn_test.go index d6bc1e9d4..ac7a7f67c 100644 --- a/clientv3/txn_test.go +++ b/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()