Beispiel #1
0
// SCARD
func (m *Miniredis) cmdScard(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteZero()
			return
		}

		if db.t(key) != "set" {
			out.WriteErrorString(ErrWrongType.Error())
			return
		}

		members := db.setMembers(key)
		out.WriteInt(len(members))
	})
}
Beispiel #2
0
// RPOP
func (m *Miniredis) cmdRpop(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteNil()
			return
		}
		if db.t(key) != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		elem := db.listPop(key)
		out.WriteString(elem)
	})
}
Beispiel #3
0
// RPUSH
func (m *Miniredis) cmdRpush(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]
	args := r.Args[1:]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if db.exists(key) && db.t(key) != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		var newLen int
		for _, value := range args {
			newLen = db.listPush(key, value)
		}
		out.WriteInt(newLen)
	})
}
Beispiel #4
0
// HINCRBYFLOAT
func (m *Miniredis) cmdHincrbyfloat(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 3 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hincrbyfloat' command")
		return nil
	}
	key := r.Args[0]
	field := r.Args[1]
	delta, err := strconv.ParseFloat(r.Args[2], 64)
	if err != nil {
		setDirty(r.Client())
		out.WriteErrorString(msgInvalidFloat)
		return nil
	}

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		v, err := db.hashIncrfloat(key, field, delta)
		if err != nil {
			out.WriteErrorString(err.Error())
			return
		}
		out.WriteString(formatFloat(v))
	})
}
Beispiel #5
0
// MMSET
func (m *Miniredis) cmdHmset(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 3 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hmset' command")
		return nil
	}
	key := r.Args[0]
	args := r.Args[1:]
	if len(args)%2 != 0 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for HMSET")
		return nil
	}
	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		for len(args) > 0 {
			field := args[0]
			value := args[1]
			args = args[2:]

			db.hashSet(key, field, value)
		}
		out.WriteOK()
	})
}
Beispiel #6
0
// HKEYS
func (m *Miniredis) cmdHkeys(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hkeys' command")
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteBulkLen(0)
			return
		}
		if db.t(key) != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		fields := db.hashFields(key)
		out.WriteBulkLen(len(fields))
		for _, f := range fields {
			out.WriteString(f)
		}
	})
}
Beispiel #7
0
// HSET
func (m *Miniredis) cmdHset(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 3 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hset' command")
		return nil
	}
	key := r.Args[0]
	field := r.Args[1]
	value := r.Args[2]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		if db.hashSet(key, field, value) {
			out.WriteZero()
		} else {
			out.WriteOne()
		}
	})
}
Beispiel #8
0
// MGET
func (m *Miniredis) cmdMget(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		out.WriteBulkLen(len(r.Args))
		for _, k := range r.Args {
			if t, ok := db.keys[k]; !ok || t != "string" {
				out.WriteNil()
				continue
			}
			v, ok := db.stringKeys[k]
			if !ok {
				// Should not happen, we just checked keys[]
				out.WriteNil()
				continue
			}
			out.WriteString(v)
		}
	})
}
Beispiel #9
0
// DECR
func (m *Miniredis) cmdDecr(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		key := r.Args[0]
		if t, ok := db.keys[key]; ok && t != "string" {
			out.WriteErrorString(msgWrongType)
			return
		}
		v, err := db.stringIncr(key, -1)
		if err != nil {
			out.WriteErrorString(err.Error())
			return
		}
		// Don't touch TTL
		out.WriteInt(v)
	})
}
Beispiel #10
0
// PING
func (m *Redico) cmdPing(out *redeo.Responder, r *redeo.Request) error {
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	out.WriteInlineString("PONG")
	return nil
}
Beispiel #11
0
// GETSET
func (m *Miniredis) cmdGetset(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]
	value := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "string" {
			out.WriteErrorString(msgWrongType)
			return
		}

		old, ok := db.stringKeys[key]
		db.stringSet(key, value)
		// a GETSET clears the expire
		delete(db.expire, key)

		if !ok {
			out.WriteNil()
			return
		}
		out.WriteString(old)
		return
	})
}
Beispiel #12
0
// LPUSHX
func (m *Miniredis) cmdLpushx(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'lpushx' command")
		return nil
	}
	key := r.Args[0]
	value := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteZero()
			return
		}
		if db.t(key) != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		newLen := db.listLpush(key, value)
		out.WriteInt(newLen)
	})
}
Beispiel #13
0
// LPOP
func (m *Miniredis) cmdLpop(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'lpop' command")
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			// Non-existing key is fine.
			out.WriteNil()
			return
		}
		if db.t(key) != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		elem := db.listLpop(key)
		out.WriteString(elem)
	})
}
Beispiel #14
0
// SDIFF
func (m *Miniredis) cmdSdiff(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	keys := r.Args

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		set, err := db.setDiff(keys)
		if err != nil {
			out.WriteErrorString(err.Error())
			return
		}

		out.WriteBulkLen(len(set))
		for k := range set {
			out.WriteString(k)
		}
	})
}
Beispiel #15
0
// SCARD
func (m *Miniredis) cmdScard(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'scard' command")
		return nil
	}

	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteZero()
			return
		}

		if db.t(key) != "set" {
			out.WriteErrorString(ErrWrongType.Error())
			return
		}

		members := db.setMembers(key)
		out.WriteInt(len(members))
	})
}
Beispiel #16
0
// APPEND
func (m *Miniredis) cmdAppend(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	key := r.Args[0]
	value := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "string" {
			out.WriteErrorString(msgWrongType)
			return
		}

		newValue := db.stringKeys[key] + value
		db.stringSet(key, newValue)

		out.WriteInt(len(newValue))
	})
}
Beispiel #17
0
// HEXISTS
func (m *Miniredis) cmdHexists(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hexists' command")
		return nil
	}
	key := r.Args[0]
	field := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		t, ok := db.keys[key]
		if !ok {
			out.WriteInt(0)
			return
		}
		if t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		if _, ok := db.hashKeys[key][field]; !ok {
			out.WriteInt(0)
			return
		}
		out.WriteInt(1)
	})
}
Beispiel #18
0
// MOVE
func (m *Miniredis) cmdMove(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	key := r.Args[0]
	targetDB, err := strconv.Atoi(r.Args[1])
	if err != nil {
		targetDB = 0
	}

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		if ctx.selectedDB == targetDB {
			out.WriteErrorString("ERR source and destination objects are the same")
			return
		}
		db := m.db(ctx.selectedDB)
		targetDB := m.db(targetDB)

		if !db.move(key, targetDB) {
			out.WriteZero()
			return
		}
		out.WriteOne()
	})
}
Beispiel #19
0
// HVALS
func (m *Miniredis) cmdHvals(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hvals' command")
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		t, ok := db.keys[key]
		if !ok {
			out.WriteBulkLen(0)
			return
		}
		if t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		out.WriteBulkLen(len(db.hashKeys[key]))
		for _, v := range db.hashKeys[key] {
			out.WriteString(v)
		}
	})
}
Beispiel #20
0
// RANDOMKEY
func (m *Miniredis) cmdRandomkey(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 0 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if len(db.keys) == 0 {
			out.WriteNil()
			return
		}
		nr := rand.Intn(len(db.keys))
		for k := range db.keys {
			if nr == 0 {
				out.WriteString(k)
				return
			}
			nr--
		}
	})
}
Beispiel #21
0
// HMGET
func (m *Miniredis) cmdHmget(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 2 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hmget' command")
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		f, ok := db.hashKeys[key]
		if !ok {
			f = map[string]string{}
		}

		out.WriteBulkLen(len(r.Args) - 1)
		for _, k := range r.Args[1:] {
			v, ok := f[k]
			if !ok {
				out.WriteNil()
				continue
			}
			out.WriteString(v)
		}
	})
}
Beispiel #22
0
// RENAMENX
func (m *Miniredis) cmdRenamenx(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	from := r.Args[0]
	to := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(from) {
			out.WriteErrorString(msgKeyNotFound)
			return
		}

		if db.exists(to) {
			out.WriteZero()
			return
		}

		db.rename(from, to)
		out.WriteOne()
	})
}
Beispiel #23
0
// HSETNX
func (m *Miniredis) cmdHsetnx(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 3 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'hsetnx' command")
		return nil
	}
	key := r.Args[0]
	field := r.Args[1]
	value := r.Args[2]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if t, ok := db.keys[key]; ok && t != "hash" {
			out.WriteErrorString(msgWrongType)
			return
		}

		if _, ok := db.hashKeys[key]; !ok {
			db.hashKeys[key] = map[string]string{}
			db.keys[key] = "hash"
		}
		_, ok := db.hashKeys[key][field]
		if ok {
			out.WriteZero()
			return
		}
		db.hashKeys[key][field] = value
		db.keyVersion[key]++
		out.WriteOne()
	})
}
Beispiel #24
0
// TTL
func (m *Miniredis) cmdTTL(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if _, ok := db.keys[key]; !ok {
			// No such key
			out.WriteInt(-2)
			return
		}

		value, ok := db.expire[key]
		if !ok {
			// No expire value
			out.WriteInt(-1)
			return
		}
		out.WriteInt(value)
	})
}
Beispiel #25
0
// LLEN
func (m *Miniredis) cmdLlen(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 1 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		t, ok := db.keys[key]
		if !ok {
			// No such key. That's zero length.
			out.WriteZero()
			return
		}
		if t != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		out.WriteInt(len(db.listKeys[key]))
	})
}
Beispiel #26
0
// SISMEMBER
func (m *Miniredis) cmdSismember(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'sismember' command")
		return nil
	}

	key := r.Args[0]
	value := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteZero()
			return
		}

		if db.t(key) != "set" {
			out.WriteErrorString(ErrWrongType.Error())
			return
		}

		if db.setIsMember(key, value) {
			out.WriteOne()
			return
		}
		out.WriteZero()
	})
}
Beispiel #27
0
// RPOPLPUSH
func (m *Miniredis) cmdRpoplpush(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	src := r.Args[0]
	dst := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(src) {
			out.WriteNil()
			return
		}
		if db.t(src) != "list" || (db.exists(dst) && db.t(dst) != "list") {
			out.WriteErrorString(msgWrongType)
			return
		}
		elem := db.listPop(src)
		db.listLpush(dst, elem)
		out.WriteString(elem)
	})
}
Beispiel #28
0
// SREM
func (m *Miniredis) cmdSrem(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 2 {
		setDirty(r.Client())
		out.WriteErrorString("ERR wrong number of arguments for 'srem' command")
		return nil
	}

	key := r.Args[0]
	fields := r.Args[1:]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteInt(0)
			return
		}

		if db.t(key) != "set" {
			out.WriteErrorString(ErrWrongType.Error())
			return
		}

		out.WriteInt(db.setRem(key, fields...))
	})
}
Beispiel #29
0
// RPUSHX
func (m *Miniredis) cmdRpushx(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) != 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}
	key := r.Args[0]
	value := r.Args[1]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		if !db.exists(key) {
			out.WriteZero()
			return
		}
		if db.t(key) != "list" {
			out.WriteErrorString(msgWrongType)
			return
		}

		newLen := db.listPush(key, value)
		out.WriteInt(newLen)
	})
}
Beispiel #30
0
// SUNIONSTORE
func (m *Miniredis) cmdSunionstore(out *redeo.Responder, r *redeo.Request) error {
	if len(r.Args) < 2 {
		setDirty(r.Client())
		return r.WrongNumberOfArgs()
	}
	if !m.handleAuth(r.Client(), out) {
		return nil
	}

	dest := r.Args[0]
	keys := r.Args[1:]

	return withTx(m, out, r, func(out *redeo.Responder, ctx *connCtx) {
		db := m.db(ctx.selectedDB)

		set, err := db.setUnion(keys)
		if err != nil {
			out.WriteErrorString(err.Error())
			return
		}

		db.del(dest, true)
		db.setSet(dest, set)
		out.WriteInt(len(set))
	})
}