Created outward-facing API or generic module commands

This commit is contained in:
Kelvin Mwinuka
2024-03-28 19:36:55 +08:00
parent 0a70104d78
commit ede32b481f
3 changed files with 309 additions and 1 deletions

View File

@@ -219,3 +219,45 @@ func FilterExpiredKeys(state map[string]KeyData) map[string]KeyData {
} }
return state return state
} }
func EncodeCommand(cmd []string) []byte {
res := fmt.Sprintf("*%d\r\n", len(cmd))
for _, token := range cmd {
res += fmt.Sprintf("$%d\r\n%s\r\n", len(token), token)
}
return []byte(res)
}
func ParseStringResponse(b []byte) (string, error) {
r := resp.NewReader(bytes.NewReader(b))
v, _, err := r.ReadValue()
if err != nil {
return "", err
}
return v.String(), nil
}
func ParseIntegerResponse(b []byte) (int, error) {
r := resp.NewReader(bytes.NewReader(b))
v, _, err := r.ReadValue()
if err != nil {
return 0, err
}
return v.Integer(), nil
}
func ParseArrayResponse(b []byte) ([]string, error) {
r := resp.NewReader(bytes.NewReader(b))
v, _, err := r.ReadValue()
if err != nil {
return nil, err
}
if v.IsNull() {
return []string{}, nil
}
arr := make([]string, len(v.Array()))
for i, e := range v.Array() {
arr[i] = e.String()
}
return arr, nil
}

View File

@@ -13,3 +13,269 @@
// limitations under the License. // limitations under the License.
package echovault package echovault
import (
"github.com/echovault/echovault/internal"
"strconv"
)
type SETOptions struct {
NX bool
XX bool
LT bool
GT bool
GET bool
EX int
PX int
EXAT int
PXAT int
}
type EXPIREOptions struct {
NX bool
XX bool
LT bool
GT bool
}
type PEXPIREOptions EXPIREOptions
type EXPIREATOptions EXPIREOptions
type PEXPIREATOptions EXPIREOptions
func (server *EchoVault) SET(key, value string, options SETOptions) (string, error) {
cmd := []string{"SET", key, value}
switch {
case options.NX:
cmd = append(cmd, "NX")
case options.XX:
cmd = append(cmd, "XX")
}
switch {
case options.EX != 0:
cmd = append(cmd, []string{"EX", strconv.Itoa(options.EX)}...)
case options.PX != 0:
cmd = append(cmd, []string{"PX", strconv.Itoa(options.PX)}...)
case options.EXAT != 0:
cmd = append(cmd, []string{"EXAT", strconv.Itoa(options.EXAT)}...)
case options.PXAT != 0:
cmd = append(cmd, []string{"PXAT", strconv.Itoa(options.PXAT)}...)
}
if options.GET {
cmd = append(cmd, "GET")
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return "", err
}
return internal.ParseStringResponse(b)
}
func (server *EchoVault) MSET(kvPairs map[string]string) (string, error) {
cmd := []string{"MSET"}
for k, v := range kvPairs {
cmd = append(cmd, []string{k, v}...)
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return "", err
}
return internal.ParseStringResponse(b)
}
func (server *EchoVault) GET(key string) (string, error) {
encoded := internal.EncodeCommand([]string{"GET", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return "", err
}
return internal.ParseStringResponse(b)
}
func (server *EchoVault) MGET(keys []string) ([]string, error) {
encoded := internal.EncodeCommand(append([]string{"MGET"}, keys...))
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return []string{}, err
}
return internal.ParseArrayResponse(b)
}
func (server *EchoVault) DEL(keys []string) (int, error) {
encoded := internal.EncodeCommand(append([]string{"DEL"}, keys...))
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) PERSIST(key string) (int, error) {
encoded := internal.EncodeCommand([]string{"PERSIST", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) EXPIRETIME(key string) (int, error) {
encoded := internal.EncodeCommand([]string{"EXPIRETIME", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) PEXPIRETIME(key string) (int, error) {
encoded := internal.EncodeCommand([]string{"PEXPIRETIME", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) TTL(key string) (int, error) {
encoded := internal.EncodeCommand([]string{"TTL", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) PTTL(key string) (int, error) {
encoded := internal.EncodeCommand([]string{"PTTL", key})
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) EXPIRE(key string, seconds int, options EXPIREOptions) (int, error) {
cmd := []string{"EXPIRE", key, strconv.Itoa(seconds)}
switch {
case options.NX:
cmd = append(cmd, "NX")
case options.XX:
cmd = append(cmd, "XX")
case options.LT:
cmd = append(cmd, "LT")
case options.GT:
cmd = append(cmd, "GT")
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) PEXPIRE(key string, milliseconds int, options PEXPIREOptions) (int, error) {
cmd := []string{"PEXPIRE", key, strconv.Itoa(milliseconds)}
switch {
case options.NX:
cmd = append(cmd, "NX")
case options.XX:
cmd = append(cmd, "XX")
case options.LT:
cmd = append(cmd, "LT")
case options.GT:
cmd = append(cmd, "GT")
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) EXPIREAT(key string, unixSeconds int, options EXPIREATOptions) (int, error) {
cmd := []string{"EXPIREAT", key, strconv.Itoa(unixSeconds)}
switch {
case options.NX:
cmd = append(cmd, "NX")
case options.XX:
cmd = append(cmd, "XX")
case options.LT:
cmd = append(cmd, "LT")
case options.GT:
cmd = append(cmd, "GT")
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}
func (server *EchoVault) PEXPIREAT(key string, unixMilliseconds int, options PEXPIREATOptions) (int, error) {
cmd := []string{"PEXPIREAT", key, strconv.Itoa(unixMilliseconds)}
switch {
case options.NX:
cmd = append(cmd, "NX")
case options.XX:
cmd = append(cmd, "XX")
case options.LT:
cmd = append(cmd, "LT")
case options.GT:
cmd = append(cmd, "GT")
}
encoded := internal.EncodeCommand(cmd)
b, err := server.handleCommand(server.context, encoded, nil, false)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}

View File

@@ -524,7 +524,7 @@ PXAT - Expire at the exat time in unix milliseconds (positive integer).`,
{ {
Command: "mget", Command: "mget",
Categories: []string{utils.ReadCategory, utils.FastCategory}, Categories: []string{utils.ReadCategory, utils.FastCategory},
Description: "(MGET key1 [key2]) Get multiple values from the specified keys.", Description: "(MGET key [key ...]) Get multiple values from the specified keys.",
Sync: false, Sync: false,
KeyExtractionFunc: mgetKeyFunc, KeyExtractionFunc: mgetKeyFunc,
HandlerFunc: handleMGet, HandlerFunc: handleMGet,