org.springframework.data.redis.core.RedisCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-data-redis Show documentation
Show all versions of spring-data-redis Show documentation
Spring Data module for Redis
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* {@link Enum Enumeration} of well-known {@literal Redis commands}. This enumeration serves as non-exhaustive set of
* built-in commands for a typical Redis server.
*
* @author Christoph Strobl
* @author Thomas Darimont
* @author Ninad Divadkar
* @author Mark Paluch
* @author Oscar Cai
* @author Sébastien Volle
* @author John Blum
* @since 1.3
* @link Redis
* command list
*/
public enum RedisCommand {
// -- A
APPEND("rw", 2, 2), //
AUTH("rw", 1, 1), //
// -- B
BGREWRITEAOF("r", 0, 0, "bgwriteaof"), //
BGSAVE("r", 0, 0), //
BITCOUNT("r", 1, 3), //
BITOP("rw", 3), //
BITPOS("r", 2, 4), //
BLPOP("rw", 2), //
BRPOP("rw", 2), //
BRPOPLPUSH("rw", 3), //
// -- C
CLIENT_KILL("rw", 1, 1), //
CLIENT_LIST("r", 0, 0), //
CLIENT_GETNAME("r", 0, 0), //
CLIENT_PAUSE("rw", 1, 1), //
CLIENT_SETNAME("w", 1, 1), //
CONFIG_GET("r", 1, 1, "getconfig"), //
CONFIG_REWRITE("rw", 0, 0), //
CONFIG_SET("w", 2, 2, "setconfig"), //
CONFIG_RESETSTAT("w", 0, 0, "resetconfigstats"), //
// -- D
DBSIZE("r", 0, 0), //
DECR("w", 1, 1), //
DECRBY("w", 2, 2), //
DEL("rw", 1), //
DISCARD("rw", 0, 0), //
DUMP("r", 1, 1), //
// -- E
ECHO("r", 1, 1), //
EVAL("rw", 2), //
EVALSHA("rw", 2), //
EXEC("rw", 0, 0), //
EXISTS("r", 1, 1), //
EXPIRE("rw", 2, 2), //
EXPIREAT("rw", 2, 2), //
// -- F
FLUSHALL("w", 0, 0), //
FLUSHDB("w", 0, 0), //
// -- G
GET("r", 1, 1), //
GETBIT("r", 2, 2), //
GETRANGE("r", 3, 3), //
GETSET("rw", 2, 2), //
GEOADD("w", 3), //
GEODIST("r", 2), //
GEOHASH("r", 2), //
GEOPOS("r", 2), //
GEORADIUS("r", 4), //
GEORADIUSBYMEMBER("r", 3), //
// -- H
HDEL("rw", 2), //
HEXISTS("r", 2, 2), //
HGET("r", 2, 2), //
HGETALL("r", 1, 1), //
HINCRBY("rw", 3, 3), //
HINCBYFLOAT("rw", 3, 3), //
HKEYS("r", 1), //
HLEN("r", 1), //
HMGET("r", 2), //
HMSET("w", 3), //
HSET("w", 3, 3), //
HSETNX("w", 3, 3), //
HVALS("r", 1, 1), //
// -- I
INCR("rw", 1), //
INCRBYFLOAT("rw", 2, 2), //
INFO("r", 0), //
// -- K
KEYS("r", 1), //
// -- L
LASTSAVE("r", 0), //
LINDEX("r", 2, 2), //
LINSERT("rw", 4, 4), //
LLEN("r", 1, 1), //
LPOP("rw", 1, 1), //
LPUSH("rw", 2), //
LPUSHX("rw", 2), //
LRANGE("r", 3, 3), //
LREM("rw", 3, 3), //
LSET("w", 3, 3), //
LTRIM("w", 3, 3), //
// -- M
MGET("r", 1), //
MIGRATE("rw", 0), //
MONITOR("rw", 0, 0), //
MOVE("rw", 2, 2), //
MSET("w", 2), //
MSETNX("w", 2), //
MULTI("rw", 0, 0), //
// -- P
PERSIST("rw", 1, 1), //
PEXPIRE("rw", 2, 2), //
PEXPIREAT("rw", 2, 2), //
PING("r", 0, 0), //
PSETEX("w", 3), //
PSUBSCRIBE("r", 1), //
PTTL("r", 1, 1), //
// -- Q
QUIT("rw", 0, 0), //
// -- R
RANDOMKEY("r", 0, 0), //
RENAME("w", 2, 2), //
RENAMENX("w", 2, 2), //
REPLICAOF("w", 2), //
RESTORE("w", 3, 3), //
RPOP("rw", 1, 1), //
RPOPLPUSH("rw", 2, 2), //
RPUSH("rw", 2), //
RPUSHX("rw", 2, 2), //
// -- S
SADD("rw", 2), //
SAVE("rw", 0, 0), //
SCARD("r", 1, 1), //
SCRIPT_EXISTS("r", 1), //
SCRIPT_FLUSH("rw", 0, 0), //
SCRIPT_KILL("rw", 0, 0), //
SCRIPT_LOAD("rw", 1, 1), //
SDIFF("r", 1), //
SDIFFSTORE("rw", 2), //
SELECT("rw", 1, 1), //
SET("w", 2), //
SETBIT("rw", 3, 3), //
SETEX("w", 3, 3), //
SETNX("w", 2, 2), //
SETRANGE("rw", 3, 3), //
SHUTDOWN("rw", 0), //
SINTER("r", 1), //
SINTERSTORE("rw", 2), //
SISMEMBER("r", 2), //
SLAVEOF("w", 2), //
SLOWLOG("rw", 1), //
SMEMBERS("r", 1, 1), //
SMOVE("rw", 3, 3), //
SORT("rw", 1), //
SPOP("rw", 1, 1), //
SRANDMEMBER("r", 1, 1), //
SREM("rw", 2), //
STRLEN("r", 1, 1), //
SUBSCRIBE("rw", 1), //
SUNION("r", 1), //
SUNIONSTORE("rw ", 2), //
SYNC("rw", 0, 0), //
// -- T
TIME("r", 0, 0), //
TTL("r", 1, 1), //
TYPE("r", 1, 1), //
// -- U
UNSUBSCRIBE("rw", 0), //
UNWATCH("rw", 0, 0), //
// -- W
WATCH("rw", 1), //
// -- Z
ZADD("rw", 3), //
ZCARD("r", 1), //
ZCOUNT("r", 3, 3), //
ZINCRBY("rw", 3), //
ZINTERSTORE("rw", 3), //
ZRANGE("r", 3), //
ZRANGEBYSCORE("r", 3), //
ZRANK("r", 2, 2), //
ZREM("rw", 2), //
ZREMRANGEBYRANK("rw", 3, 3), //
ZREMRANGEBYSCORE("rw", 3, 3), //
ZREVRANGE("r", 3), //
ZREVRANGEBYSCORE("r", 3), //
ZREVRANK("r", 2, 2), //
ZSCORE("r", 2, 2), //
ZUNIONSTORE("rw", 3), //
SCAN("r", 1), //
SSCAN("r", 2), //
HSCAN("r", 2), //
ZSCAN("r", 2), //
// -- UNKNOWN / DEFAULT
UNKNOWN("rw", -1);
private static final Map commandLookup;
static {
commandLookup = buildCommandLookupTable();
}
private static Map buildCommandLookupTable() {
RedisCommand[] commands = RedisCommand.values();
Map map = new HashMap<>(commands.length + 5, 1.0f);
for (RedisCommand command : commands) {
map.put(command.name().toLowerCase(), command);
if (!ObjectUtils.isEmpty(command.alias)) {
map.put(command.alias, command);
}
}
return Collections.unmodifiableMap(map);
}
/**
* Returns the command represented by the given {@code key}, otherwise returns {@link #UNKNOWN} if no matching command
* could be found.
*
* @param key {@link String key} to the {@link RedisCommand} to lookup.
* @return a matching {@link RedisCommand} for the given {@code key}, otherwise {@link #UNKNOWN}.
*/
public static RedisCommand failsafeCommandLookup(String key) {
return StringUtils.hasText(key) ? commandLookup.getOrDefault(key.toLowerCase(), UNKNOWN) : UNKNOWN;
}
private final boolean read;
private final boolean write;
private final int minArgs;
private final int maxArgs;
private final @Nullable String alias;
/**
* Creates a new {@link RedisCommand}.
*
* @param mode {@link String} containing the mode ({@literal r} for read, {@literal w} for write or {@literal rw} for
* read-write) of the Redis command.
* @param minArgs minimum number of arguments accepted by the Redis command.
*/
RedisCommand(String mode, int minArgs) {
this(mode, minArgs, -1);
}
/**
* Creates a new {@link RedisCommand}.
*
* @param mode {@link String} containing the mode ({@literal r} for read, {@literal w} for write or {@literal rw} for
* read-write) of the Redis command.
* @param minArgs minimum number of arguments accepted by the Redis command.
* @param maxArgs maximum number of arguments accepted by the Redis command.
*/
RedisCommand(String mode, int minArgs, int maxArgs) {
this(mode, minArgs, maxArgs, null);
}
/**
* Creates a new {@link RedisCommand}.
*
* @param mode {@link String} containing the mode ({@literal r} for read, {@literal w} for write or {@literal rw} for
* read-write) of the Redis command.
* @param minArgs minimum number of arguments accepted by the Redis command.
* @param maxArgs maximum number of arguments accepted by the Redis command.
* @param alias alternate command name used as alias for the Redis command, can be {@literal null}.
*/
RedisCommand(String mode, int minArgs, int maxArgs, @Nullable String alias) {
if (StringUtils.hasText(mode)) {
this.read = mode.toLowerCase().contains("r");
this.write = mode.toLowerCase().contains("w");
} else {
this.read = true;
this.write = true;
}
this.minArgs = minArgs;
this.maxArgs = maxArgs;
this.alias = alias;
}
/**
* @return {@literal true} if the command requires arguments
*/
public boolean requiresArguments() {
return minArgs >= 0;
}
/**
* @return {@literal true} if an exact number of arguments is expected.
*/
public boolean requiresExactNumberOfArguments() {
return maxArgs == 0 || minArgs == maxArgs;
}
/**
* Returns a {@link Set} of all {@link String aliases} for this {@link RedisCommand}.
*
* @return a {@link Set} of all {@link String aliases} for this {@link RedisCommand}.
*/
Set getAliases() {
return ObjectUtils.isEmpty(this.alias) ? Collections.emptySet() : Collections.singleton(this.alias);
}
/**
* @return {@literal true} if the command triggers a read operation
*/
public boolean isRead() {
return read;
}
/**
* @return {@literal true} if the command triggers a write operation
*/
public boolean isWrite() {
return write;
}
/**
* @return {@literal true} if values are read but not written
*/
public boolean isReadonly() {
return isRead() && !isWrite();
}
/**
* {@link String#equalsIgnoreCase(String) Compares} the given {@link String} representing the {@literal Redis command}
* to the {@link #toString()} representation of {@link RedisCommand} as well as any {@link #alias}.
*
* @param command {@link String} representation of the {@literal Redis command} to match.
* @return {@literal true} if a positive match.
*/
public boolean isRepresentedBy(String command) {
return StringUtils.hasText(command)
&& (toString().equalsIgnoreCase(command) || command.toLowerCase().equals(this.alias));
}
/**
* Validates given {@link Integer argument count} against expected ones.
*
* @param argumentCount {@link Integer number of arguments} passed to the Redis command.
* @exception IllegalArgumentException if the given {@link Integer argument count} does not match expected.
*/
public void validateArgumentCount(int argumentCount) {
if (requiresArguments()) {
if (requiresExactNumberOfArguments()) {
if (argumentCount != this.maxArgs) {
throw newIllegalArgumentException("%s command requires %d %s", name(), this.maxArgs, arguments(this.maxArgs));
}
}
if (argumentCount < this.minArgs) {
throw newIllegalArgumentException("%s command requires at least %d %s", name(), this.minArgs,
arguments(this.maxArgs));
}
if (this.maxArgs > 0 && argumentCount > this.maxArgs) {
throw newIllegalArgumentException("%s command requires at most %s %s", name(), this.maxArgs,
arguments(this.maxArgs));
}
}
}
private String arguments(int count) {
return count == 1 ? "argument" : "arguments";
}
private IllegalArgumentException newIllegalArgumentException(String message, Object... arguments) {
return new IllegalArgumentException(String.format(message, arguments));
}
}