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

add String method #146

Merged
merged 9 commits into from
Jul 4, 2023
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
184 changes: 180 additions & 4 deletions structure/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"github.com/ByteStorage/FlyDB/config"
"github.com/ByteStorage/FlyDB/engine"
_const "github.com/ByteStorage/FlyDB/lib/const"
"strconv"
"time"
)

Expand All @@ -13,6 +15,11 @@ type StringStructure struct {
db *engine.DB
}

var (
// ErrWrongNumberOfArguments is returned when the number of arguments is wrong
ErrWrongNumberOfArguments = errors.New("wrong number of arguments")
)

// NewStringStructure returns a new StringStructure
// It will return a nil StringStructure if the database cannot be opened
// or the database cannot be created
Expand Down Expand Up @@ -116,10 +123,6 @@ func (s *StringStructure) StrLen(key []byte) (int, error) {
}

// GetSet sets the value of a key and returns its old value
// If the key does not exist, it will be created
// If the key exists, it will be overwritten
// If the key is expired, it will be deleted
// If the key is not expired, it will be updated
func (s *StringStructure) GetSet(key, value []byte, ttl time.Duration) ([]byte, error) {
// Get the old value
oldValue, err := s.Get(key)
Expand All @@ -137,6 +140,179 @@ func (s *StringStructure) GetSet(key, value []byte, ttl time.Duration) ([]byte,
return oldValue, nil
}

// Append appends a value to the value of a key
func (s *StringStructure) Append(key, value []byte, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Append the value
newValue := append(oldValue, value...)

// Set the value
return s.Set(key, newValue, ttl)
}

// Incr increments the integer value of a key by 1
func (s *StringStructure) Incr(key []byte, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Convert the old value to an integer
oldIntValue, err := strconv.Atoi(string(oldValue))
if err != nil {
return err
}

// Increment the integer value
newIntValue := oldIntValue + 1

// Convert the new integer value to a byte slice
newValue := []byte(strconv.Itoa(newIntValue))

// Set the value
return s.Set(key, newValue, ttl)
}

// IncrBy increments the integer value of a key by the given amount
func (s *StringStructure) IncrBy(key []byte, amount int, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Convert the old value to an integer
oldIntValue, err := strconv.Atoi(string(oldValue))
if err != nil {
return err
}

// Increment the integer value
newIntValue := oldIntValue + amount

// Convert the new integer value to a byte slice
newValue := []byte(strconv.Itoa(newIntValue))

// Set the value
return s.Set(key, newValue, ttl)
}

// IncrByFloat increments the float value of a key by the given amount
func (s *StringStructure) IncrByFloat(key []byte, amount float64, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Convert the old value to a float
oldFloatValue, err := strconv.ParseFloat(string(oldValue), 64)
if err != nil {
return err
}

// Increment the float value
newFloatValue := oldFloatValue + amount

// Convert the new float value to a byte slice
newValue := []byte(strconv.FormatFloat(newFloatValue, 'f', -1, 64))

// Set the value
return s.Set(key, newValue, ttl)
}

// Decr decrements the integer value of a key by 1
func (s *StringStructure) Decr(key []byte, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Convert the old value to an integer
oldIntValue, err := strconv.Atoi(string(oldValue))
if err != nil {
return err
}

// Decrement the integer value
newIntValue := oldIntValue - 1

// Convert the new integer value to a byte slice
newValue := []byte(strconv.Itoa(newIntValue))

// Set the value
return s.Set(key, newValue, ttl)
}

// DecrBy decrements the integer value of a key by the given amount
func (s *StringStructure) DecrBy(key []byte, amount int, ttl time.Duration) error {
// Get the old value
oldValue, err := s.Get(key)
if err != nil {
return err
}

// Convert the old value to an integer
oldIntValue, err := strconv.Atoi(string(oldValue))
if err != nil {
return err
}

// Decrement the integer value
newIntValue := oldIntValue - amount

// Convert the new integer value to a byte slice
newValue := []byte(strconv.Itoa(newIntValue))

// Set the value
return s.Set(key, newValue, ttl)
}

// Exists checks if a key exists
func (s *StringStructure) Exists(key []byte) (bool, error) {
// Get the value
_, err := s.Get(key)
if err != nil {
if err == _const.ErrKeyNotFound {
return false, nil
}
return false, err
}

return true, nil
}

// Expire sets the expiration time of a key
func (s *StringStructure) Expire(key []byte, ttl time.Duration) error {
// Get the value
value, err := s.Get(key)
if err != nil {
return err
}

// Set the value
return s.Set(key, value, ttl)
}

// Persist removes the expiration time of a key
func (s *StringStructure) Persist(key []byte) error {
// Get the value
value, err := s.Get(key)
if err != nil {
return err
}

// Set the value
return s.Set(key, value, 0)
}

// encodeStringValue encodes the value
// format: [type][expire][value]
// type: 1 byte
Expand Down
151 changes: 151 additions & 0 deletions structure/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,154 @@ func TestStringStructure_GetSet(t *testing.T) {
assert.NotNil(t, value2)
assert.Equal(t, value1, value2)
}

func TestStringStructure_Append(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), randkv.RandomValue(10), 0)
//assert.Nil(t, err)
s1, _ := str.Get(randkv.GetTestKey(1))
t.Log(string(s1))

err = str.Append(randkv.GetTestKey(1), randkv.RandomValue(5), 0)
//assert.Nil(t, err)
s2, _ := str.Get(randkv.GetTestKey(1))
t.Log(string(s2))
}

func TestStringStructure_Incr(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err := str.Incr(randkv.GetTestKey(1), 0)
assert.Nil(t, err)
v1, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v1), "2")

err = str.Incr(randkv.GetTestKey(1), 0)
assert.Nil(t, err)
v2, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v2), "3")
}

func TestStringStructure_IncrBy(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err := str.IncrBy(randkv.GetTestKey(1), 10, 0)
assert.Nil(t, err)
v1, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v1), "11")

err = str.IncrBy(randkv.GetTestKey(1), 10, 0)
assert.Nil(t, err)
v2, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v2), "21")
}

func TestStringStructure_IncrByFloat(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err := str.IncrByFloat(randkv.GetTestKey(1), 1.1, 0)
assert.Nil(t, err)
v1, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v1), "2.1")

err = str.IncrByFloat(randkv.GetTestKey(1), 1.1, 0)
assert.Nil(t, err)
v2, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v2), "3.2")
}

func TestStringStructure_Decr(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err := str.Decr(randkv.GetTestKey(1), 0)
assert.Nil(t, err)
v1, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v1), "0")

err = str.Decr(randkv.GetTestKey(1), 0)
assert.Nil(t, err)
v2, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v2), "-1")
}

func TestStringStructure_DecrBy(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err := str.DecrBy(randkv.GetTestKey(1), 10, 0)
assert.Nil(t, err)
v1, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v1), "-9")

err = str.DecrBy(randkv.GetTestKey(1), 10, 0)
assert.Nil(t, err)
v2, _ := str.Get(randkv.GetTestKey(1))
assert.Equal(t, string(v2), "-19")
}

func TestStringStructure_Exists(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

ok1, err := str.Exists(randkv.GetTestKey(1))
assert.Nil(t, err)
assert.Equal(t, ok1, true)

ok2, err := str.Exists(randkv.GetTestKey(1))
assert.Nil(t, err)
assert.Equal(t, ok2, true)
}

func TestStringStructure_Expire(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err = str.Expire(randkv.GetTestKey(1), 1*time.Second)
assert.Nil(t, err)
v1, err := str.Get(randkv.GetTestKey(1))
assert.Nil(t, err)
assert.Equal(t, string(v1), "1")

time.Sleep(2 * time.Second)
v2, err := str.Get(randkv.GetTestKey(1))
assert.Equal(t, err, ErrKeyExpired)
assert.Equal(t, string(v2), "")
}

func TestStringStructure_Persist(t *testing.T) {
str := initdb()

err = str.Set(randkv.GetTestKey(1), []byte("1"), 0)
assert.Nil(t, err)

err = str.Expire(randkv.GetTestKey(1), 1*time.Second)
assert.Nil(t, err)
v1, err := str.Get(randkv.GetTestKey(1))
assert.Nil(t, err)
assert.Equal(t, string(v1), "1")

err = str.Persist(randkv.GetTestKey(1))
assert.Nil(t, err)
v2, err := str.Get(randkv.GetTestKey(1))
assert.Nil(t, err)
assert.Equal(t, string(v2), "1")
}