Skip to content

Commit

Permalink
Merge pull request ByteStorage#146 from ByteStorage/godqi-dev
Browse files Browse the repository at this point in the history
add String method
  • Loading branch information
qishenonly authored Jul 4, 2023
2 parents d51b930 + 5ffeb82 commit f18c4cc
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 4 deletions.
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")
}

0 comments on commit f18c4cc

Please sign in to comment.