Skip to content

Commit

Permalink
Commands added for QREF
Browse files Browse the repository at this point in the history
  • Loading branch information
arpitbbhayani committed Nov 18, 2022
1 parent bb570b2 commit 226d3e8
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 2 deletions.
131 changes: 131 additions & 0 deletions core/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,129 @@ func evalQINTPEEK(args []string) []byte {
return Encode(q.Iterate(int(num)), false)
}

// evalQREFINS inserts the reference of the provided key identified by key
// first argument will be the key, that should be of type `QREF`
// second argument will be the key that needs to be added to the queueref
// if the queue does not exist, evalQREFINS will also create the queueref
// returns true if the key reference was inserted
// returns false otherwise
func evalQREFINS(args []string) []byte {
if len(args) != 2 {
return Encode(errors.New("ERR invalid number of arguments for `QREFINS` command"), false)
}

obj := Get(args[0])
if obj == nil {
obj = NewObj(NewQueueRef(), -1, OBJ_TYPE_BYTELIST, OBJ_ENCODING_QREF)
}

if err := assertType(obj.TypeEncoding, OBJ_TYPE_BYTELIST); err != nil {
return Encode(err, false)
}

if err := assertEncoding(obj.TypeEncoding, OBJ_ENCODING_QREF); err != nil {
return Encode(err, false)
}

Put(args[0], obj)

q := obj.Value.(*QueueRef)
return Encode(q.Insert(args[1]), false)
}

// evalQREFREM removes the element from the QREF identified by key
// first argument will be the key, that should be of type `QREF`
// if the key does not exist, evalQREFREM returns nil otherwise it
// returns the RESP encoded value of the key reference from the queue
// if we remove from the empty queue, nil is returned
func evalQREFREM(args []string) []byte {
if len(args) != 1 {
return Encode(errors.New("ERR invalid number of arguments for `QREFREM` command"), false)
}

obj := Get(args[0])
if obj == nil {
return RESP_NIL
}

if err := assertType(obj.TypeEncoding, OBJ_TYPE_BYTELIST); err != nil {
return Encode(err, false)
}

if err := assertEncoding(obj.TypeEncoding, OBJ_ENCODING_QREF); err != nil {
return Encode(err, false)
}

q := obj.Value.(*QueueRef)
x, err := q.Remove()

if err == ErrQueueEmpty {
return RESP_NIL
}

return Encode(x.Value, false)
}

// evalQREFLEN returns the length of the QREF identified by key
// returns the integer value indicating the length of the queue
// if the key does not exist, the response is 0
func evalQREFLEN(args []string) []byte {
if len(args) != 1 {
return Encode(errors.New("ERR invalid number of arguments for `QREFLEN` command"), false)
}

obj := Get(args[0])
if obj == nil {
return RESP_ZERO
}

if err := assertType(obj.TypeEncoding, OBJ_TYPE_BYTELIST); err != nil {
return Encode(err, false)
}

if err := assertEncoding(obj.TypeEncoding, OBJ_ENCODING_QREF); err != nil {
return Encode(err, false)
}

q := obj.Value.(*QueueRef)
return Encode(q.qi.Length, false)
}

// evalQREFPEEK peeks into the QREF and returns 5 elements without popping them
// returns the array of resp encoded values as the response.
// if the key does not exist, then we return an empty array
func evalQREFPEEK(args []string) []byte {
var num int64 = 5
var err error

if len(args) > 2 {
return Encode(errors.New("ERR invalid number of arguments for `QREFPEEK` command"), false)
}

if len(args) == 2 {
num, err = strconv.ParseInt(args[1], 10, 32)
if err != nil || num <= 0 || num > 100 {
return Encode(errors.New("ERR number of elements to peek should be a positive number less than 100"), false)
}
}

obj := Get(args[0])
if obj == nil {
return RESP_EMPTY_ARRAY
}

if err := assertType(obj.TypeEncoding, OBJ_TYPE_BYTELIST); err != nil {
return Encode(err, false)
}

if err := assertEncoding(obj.TypeEncoding, OBJ_ENCODING_QREF); err != nil {
return Encode(err, false)
}

q := obj.Value.(*QueueRef)
return Encode(q.Iterate(int(num)), false)
}

func executeCommand(cmd *RedisCmd, c *Client) []byte {
switch cmd.Cmd {
case "PING":
Expand Down Expand Up @@ -468,6 +591,14 @@ func executeCommand(cmd *RedisCmd, c *Client) []byte {
return evalQINTLEN(cmd.Args)
case "QINTPEEK":
return evalQINTPEEK(cmd.Args)
case "QREFINS":
return evalQINTINS(cmd.Args)
case "QREFREM":
return evalQINTREM(cmd.Args)
case "QREFLEN":
return evalQINTLEN(cmd.Args)
case "QREFPEEK":
return evalQINTPEEK(cmd.Args)
case "MULTI":
c.TxnBegin()
return evalMULTI(cmd.Args)
Expand Down
1 change: 1 addition & 0 deletions core/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var OBJ_ENCODING_EMBSTR uint8 = 8

var OBJ_TYPE_BYTELIST uint8 = 1 << 4
var OBJ_ENCODING_QINT uint8 = 0
var OBJ_ENCODING_QREF uint8 = 1

func ExtractTypeEncoding(obj *Obj) (uint8, uint8) {
return obj.TypeEncoding & 0b11110000, obj.TypeEncoding & 0b00001111
Expand Down
2 changes: 0 additions & 2 deletions core/queueref.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"unsafe"
)

const QueueRefMaxBuf int = 256

type QueueRef struct {
qi *QueueInt
}
Expand Down
7 changes: 7 additions & 0 deletions core/resp.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ func Encode(value interface{}, isSimple bool) []byte {
buf.Write(encodeString(b))
}
return []byte(fmt.Sprintf("*%d\r\n%s", len(v), buf.Bytes()))
case []*Obj:
var b []byte
buf := bytes.NewBuffer(b)
for _, b := range value.([]*Obj) {
buf.Write(Encode(b.Value, false))
}
return []byte(fmt.Sprintf("*%d\r\n%s", len(v), buf.Bytes()))
case []interface{}:
var b []byte
buf := bytes.NewBuffer(b)
Expand Down

0 comments on commit 226d3e8

Please sign in to comment.