Skip to content

Commit

Permalink
Use functional options instead
Browse files Browse the repository at this point in the history
  • Loading branch information
steveh committed Nov 11, 2021
1 parent 163ad87 commit 622af90
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 66 deletions.
129 changes: 65 additions & 64 deletions kv.go
Expand Up @@ -45,18 +45,14 @@ type KeyValue interface {
Put(key string, value []byte) (revision uint64, err error)
// PutString will place the string for the key into the store.
PutString(key string, value string) (revision uint64, err error)
// Create will add the key/value pair if it does not exist.
// Create will add the key/value pair iff it does not exist.
Create(key string, value []byte) (revision uint64, err error)
// Update will update the value if the latest revision matches.
// Update will update the value iff the latest revision matches.
Update(key string, value []byte, last uint64) (revision uint64, err error)
// Delete will place a delete marker and leave all revisions.
Delete(key string) error
// DeleteCond will place a delete marker and leave all revision if the latest revision matches.
DeleteCond(key string, last uint64) error
Delete(key string, opts ...DeleteOpt) error
// Purge will place a delete marker and remove all previous revisions.
Purge(key string) error
// PurgeCond will place a delete marker and remove all previous revisions if the latest revision matches.
PurgeCond(key string, last uint64) error
Purge(key string, opts ...DeleteOpt) error
// Watch for any updates to keys that match the keys argument which could include wildcards.
// Watch will send a nil entry when it has received all initial values.
Watch(keys string, opts ...WatchOpt) (KeyWatcher, error)
Expand Down Expand Up @@ -150,6 +146,39 @@ func MetaOnly() WatchOpt {
})
}

type DeleteOpt interface {
configureDelete(opts *deleteOpts) error
}

type deleteOpts struct {
// Remove all previous revisions.
purge bool
// Delete only if the latest revision matches.
revision uint64
}

type deleteOptFn func(opts *deleteOpts) error

func (opt deleteOptFn) configureDelete(opts *deleteOpts) error {
return opt(opts)
}

// LastRevision deletes if the latest revision matches.
func LastRevision(revision uint64) DeleteOpt {
return deleteOptFn(func(opts *deleteOpts) error {
opts.revision = revision
return nil
})
}

// Purge removes all previous revisions.
func Purge() DeleteOpt {
return deleteOptFn(func(opts *deleteOpts) error {
opts.purge = true
return nil
})
}

// KeyValueConfig is for configuring a KeyValue store.
type KeyValueConfig struct {
Bucket string
Expand Down Expand Up @@ -441,7 +470,7 @@ func (kv *kvs) PutString(key string, value string) (revision uint64, err error)
return kv.Put(key, []byte(value))
}

// Create will add the key/value pair if it does not exist.
// Create will add the key/value pair iff it does not exist.
func (kv *kvs) Create(key string, value []byte) (revision uint64, err error) {
v, err := kv.Update(key, value, 0)
if err == nil {
Expand All @@ -457,7 +486,7 @@ func (kv *kvs) Create(key string, value []byte) (revision uint64, err error) {
return 0, err
}

// Update will update the value if the latest revision matches.
// Update will update the value iff the latest revision matches.
func (kv *kvs) Update(key string, value []byte, revision uint64) (uint64, error) {
if !keyValid(key) {
return 0, ErrInvalidKey
Expand All @@ -478,73 +507,45 @@ func (kv *kvs) Update(key string, value []byte, revision uint64) (uint64, error)
}

// Delete will place a delete marker and leave all revisions.
func (kv *kvs) Delete(key string) error {
m, err := kv.buildDelete(key)
if err != nil {
return err
func (kv *kvs) Delete(key string, opts ...DeleteOpt) error {
if !keyValid(key) {
return ErrInvalidKey
}

m.Header.Set(kvop, kvdel)
var b strings.Builder
b.WriteString(kv.pre)
b.WriteString(key)

_, err = kv.js.PublishMsg(m)
return err
}
// DEL op marker. For watch functionality.
m := NewMsg(b.String())

// DeleteCond will place a delete marker and leave all revisions if the latest revision matches.
func (kv *kvs) DeleteCond(key string, revision uint64) error {
m, err := kv.buildDelete(key)
if err != nil {
return err
var o deleteOpts
for _, opt := range opts {
if opt != nil {
if err := opt.configureDelete(&o); err != nil {
return err
}
}
}

m.Header.Set(kvop, kvdel)
m.Header.Set(ExpectedLastSubjSeqHdr, strconv.FormatUint(revision, 10))

_, err = kv.js.PublishMsg(m)
return err
}

// Purge will remove the key and all revisions.
func (kv *kvs) Purge(key string) error {
m, err := kv.buildDelete(key)
if err != nil {
return err
if o.purge {
m.Header.Set(kvop, kvpurge)
m.Header.Set(MsgRollup, MsgRollupSubject)
} else {
m.Header.Set(kvop, kvdel)
}

m.Header.Set(kvop, kvpurge)
m.Header.Set(MsgRollup, MsgRollupSubject)

_, err = kv.js.PublishMsg(m)
return err
}

// PurgeCond will remove the key and all revisions if the latest revision matches.
func (kv *kvs) PurgeCond(key string, revision uint64) error {
m, err := kv.buildDelete(key)
if err != nil {
return err
if o.revision != 0 {
m.Header.Set(ExpectedLastSubjSeqHdr, strconv.FormatUint(o.revision, 10))
}

m.Header.Set(kvop, kvpurge)
m.Header.Set(MsgRollup, MsgRollupSubject)
m.Header.Set(ExpectedLastSubjSeqHdr, strconv.FormatUint(revision, 10))

_, err = kv.js.PublishMsg(m)
_, err := kv.js.PublishMsg(m)
return err
}

func (kv *kvs) buildDelete(key string) (*Msg, error) {
if !keyValid(key) {
return nil, ErrInvalidKey
}

var b strings.Builder
b.WriteString(kv.pre)
b.WriteString(key)

// DEL op marker. For watch functionality.
m := NewMsg(b.String())
return m, nil
// Purge will remove the key and all revisions.
func (kv *kvs) Purge(key string, opts ...DeleteOpt) error {
return kv.Delete(key, append(opts, Purge())...)
}

// PurgeDeletes will remove all current delete markers.
Expand Down
4 changes: 2 additions & 2 deletions test/kv_test.go
Expand Up @@ -66,9 +66,9 @@ func TestKeyValueBasics(t *testing.T) {
if r != 3 {
t.Fatalf("Expected 3 for the revision, got %d", r)
}
err = kv.DeleteCond("name", 4)
err = kv.Delete("name", nats.LastRevision(4))
expectErr(t, err)
err = kv.DeleteCond("name", 3)
err = kv.Delete("name", nats.LastRevision(3))
expectOk(t, err)

// Conditional Updates.
Expand Down

0 comments on commit 622af90

Please sign in to comment.