Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TT-10949 Adding SetIfNotExist to KeyValue #108

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion persistent/model/object_id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ func TestUnmarshalJSON(t *testing.T) {

var id2 ObjectID
err = id2.UnmarshalJSON(idBytes)

if err != nil {
t.Fatal(err)
}
Expand Down
15 changes: 13 additions & 2 deletions temporal/internal/driver/redisv9/keyvalue.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ func (r *RedisV9) DeleteScanMatch(ctx context.Context, pattern string) (int64, e
case *redis.Client:
var err error
totalDeleted, err = r.deleteScanMatchSingleNode(ctx, client, pattern)

if err != nil {
if errors.Is(err, redis.ErrClosed) {
return totalDeleted, temperr.ClosedConnection
Expand All @@ -218,7 +217,6 @@ func (r *RedisV9) deleteScanMatchSingleNode(ctx context.Context, client redis.Cm

var keys []string
keys, _, err = client.Scan(ctx, cursor, pattern, 0).Result()

if err != nil {
return int64(deleted), err
}
Expand Down Expand Up @@ -479,3 +477,16 @@ func fetchKeys(ctx context.Context,

return keys, cursor, nil
}

func (r *RedisV9) SetIfNotExist(ctx context.Context, key, value string, expiration time.Duration) (bool, error) {
if key == "" {
return false, temperr.KeyEmpty
}

res := r.client.SetNX(ctx, key, value, expiration)
if res.Err() != nil {
return false, res.Err()
}

return res.Val(), nil
}
93 changes: 93 additions & 0 deletions temporal/keyvalue/keyvalue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1261,3 +1261,96 @@ func TestKeyValue_GetKeysWithOpts(t *testing.T) {
}
}
}

func TestKeyValue_SetIfNotExist(t *testing.T) {
connectors := testutil.TestConnectors(t)
defer testutil.CloseConnectors(t, connectors)

tcs := []struct {
name string
key string
value string
pre func(kv model.KeyValue)
expiration time.Duration
expectedErr error
expectedSet bool
}{
{
name: "set_with_valid_key_and_value",
key: "key1",
value: "value1",
expiration: 10 * time.Second,
expectedErr: nil,
expectedSet: true,
},
{
name: "set_with_empty_key",
key: "",
value: "value2",
expiration: 10 * time.Second,
expectedErr: temperr.KeyEmpty,
},
{
name: "set_with_empty_value",
key: "key3",
value: "",
expiration: 10 * time.Second,
expectedErr: nil,
expectedSet: true,
},
{
name: "set_with_no_expiration",
key: "key4",
value: "value4",
expiration: 10 * time.Second,
expectedErr: nil,
expectedSet: true,
},
{
name: "set_already_existing_key",
key: "key5",
value: "value5",
expiration: 10 * time.Second,
expectedErr: nil,
pre: func(kv model.KeyValue) {
t.Helper()
err := kv.Set(context.Background(), "key5", "value5", 10*time.Second)
assert.Nil(t, err)
},
expectedSet: false,
},
}

for _, connector := range connectors {
for _, tc := range tcs {
t.Run(connector.Type()+"_"+tc.name, func(t *testing.T) {
ctx := context.Background()

kv, err := NewKeyValue(connector)
assert.Nil(t, err)

flusher, err := flusher.NewFlusher(connector)
assert.Nil(t, err)
defer assert.Nil(t, flusher.FlushAll(ctx))

if tc.pre != nil {
tc.pre(kv)
}

val, err := kv.SetIfNotExist(ctx, tc.key, tc.value, tc.expiration)
assert.Equal(t, tc.expectedErr, err)
assert.Equal(t, tc.expectedSet, val)
if err == nil {
actualValue, err := kv.Get(ctx, tc.key)
assert.Nil(t, err)

assert.Equal(t, tc.value, actualValue)

actualTTL, err := kv.TTL(ctx, tc.key)
assert.Nil(t, err)
assert.True(t, actualTTL <= int64(tc.expiration.Seconds()))
}
})
}
}
}
3 changes: 3 additions & 0 deletions temporal/model/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ type KeyValue interface {
Get(ctx context.Context, key string) (value string, err error)
// Set sets the string value of a key
Set(ctx context.Context, key, value string, ttl time.Duration) error
// SetIfNotExist sets the string value of a key if the key does not exist.
// Returns true if the key was set, false otherwise.
SetIfNotExist(ctx context.Context, key, value string, expiration time.Duration) (bool, error)
// Delete removes the specified keys
Delete(ctx context.Context, key string) error
// Increment atomically increments the integer value of a key by one
Expand Down
28 changes: 28 additions & 0 deletions temporal/tempmocks/key_value.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading