use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone)]
pub enum Command {
Get {
key: Vec<u8>,
},
Set {
key: Vec<u8>,
value: Vec<u8>,
ex: Option<u64>,
px: Option<u64>,
nx: bool,
xx: bool,
},
GetSet {
key: Vec<u8>,
value: Vec<u8>,
},
Append {
key: Vec<u8>,
value: Vec<u8>,
},
Strlen {
key: Vec<u8>,
},
Incr {
key: Vec<u8>,
},
Decr {
key: Vec<u8>,
},
IncrBy {
key: Vec<u8>,
delta: i64,
},
DecrBy {
key: Vec<u8>,
delta: i64,
},
MGet {
keys: Vec<Vec<u8>>,
},
MSet {
entries: Vec<(Vec<u8>, Vec<u8>)>,
},
SetNx {
key: Vec<u8>,
value: Vec<u8>,
},
IncrByFloat {
key: Vec<u8>,
delta: f64,
},
GetRange {
key: Vec<u8>,
start: i64,
end: i64,
},
SetRange {
key: Vec<u8>,
offset: usize,
value: Vec<u8>,
},
GetDel {
key: Vec<u8>,
},
GetEx {
key: Vec<u8>,
ex: Option<u64>,
px: Option<u64>,
exat: Option<u64>,
pxat: Option<u64>,
persist: bool,
},
MSetNx {
entries: Vec<(Vec<u8>, Vec<u8>)>,
},
Del {
keys: Vec<Vec<u8>>,
},
Exists {
keys: Vec<Vec<u8>>,
},
Expire {
key: Vec<u8>,
seconds: u64,
},
PExpire {
key: Vec<u8>,
millis: u64,
},
Persist {
key: Vec<u8>,
},
Ttl {
key: Vec<u8>,
},
PTtl {
key: Vec<u8>,
},
Type {
key: Vec<u8>,
},
Keys {
pattern: String,
},
Scan {
cursor: u64,
pattern: Option<String>,
count: Option<usize>,
},
ExpireAt {
key: Vec<u8>,
timestamp: u64,
},
PExpireAt {
key: Vec<u8>,
timestamp_ms: u64,
},
Rename {
key: Vec<u8>,
newkey: Vec<u8>,
},
RenameNx {
key: Vec<u8>,
newkey: Vec<u8>,
},
Unlink {
keys: Vec<Vec<u8>>,
},
Copy {
source: Vec<u8>,
destination: Vec<u8>,
replace: bool,
},
RandomKey,
Touch {
keys: Vec<Vec<u8>>,
},
ObjectRefCount {
key: Vec<u8>,
},
ObjectIdleTime {
key: Vec<u8>,
},
ObjectHelp,
DbSize,
FlushDb,
LPush {
key: Vec<u8>,
values: Vec<Vec<u8>>,
},
RPush {
key: Vec<u8>,
values: Vec<Vec<u8>>,
},
LPop {
key: Vec<u8>,
},
RPop {
key: Vec<u8>,
},
LLen {
key: Vec<u8>,
},
LRange {
key: Vec<u8>,
start: i64,
stop: i64,
},
LIndex {
key: Vec<u8>,
index: i64,
},
LSet {
key: Vec<u8>,
index: i64,
value: Vec<u8>,
},
LInsert {
key: Vec<u8>,
before: bool,
pivot: Vec<u8>,
value: Vec<u8>,
},
LRem {
key: Vec<u8>,
count: i64,
value: Vec<u8>,
},
LTrim {
key: Vec<u8>,
start: i64,
stop: i64,
},
LPos {
key: Vec<u8>,
value: Vec<u8>,
rank: Option<i64>,
count: Option<i64>,
maxlen: Option<i64>,
},
RPopLPush {
source: Vec<u8>,
destination: Vec<u8>,
},
LMove {
source: Vec<u8>,
destination: Vec<u8>,
from_left: bool,
to_left: bool,
},
HSet {
key: Vec<u8>,
fields: Vec<(Vec<u8>, Vec<u8>)>,
},
HGet {
key: Vec<u8>,
field: Vec<u8>,
},
HDel {
key: Vec<u8>,
fields: Vec<Vec<u8>>,
},
HGetAll {
key: Vec<u8>,
},
HLen {
key: Vec<u8>,
},
HExists {
key: Vec<u8>,
field: Vec<u8>,
},
HIncrBy {
key: Vec<u8>,
field: Vec<u8>,
delta: i64,
},
HMGet {
key: Vec<u8>,
fields: Vec<Vec<u8>>,
},
HKeys {
key: Vec<u8>,
},
HVals {
key: Vec<u8>,
},
HSetNx {
key: Vec<u8>,
field: Vec<u8>,
value: Vec<u8>,
},
HIncrByFloat {
key: Vec<u8>,
field: Vec<u8>,
delta: f64,
},
HRandField {
key: Vec<u8>,
count: Option<i64>,
withvalues: bool,
},
HScan {
key: Vec<u8>,
cursor: u64,
pattern: Option<String>,
count: Option<usize>,
},
SAdd {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
SRem {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
SMembers {
key: Vec<u8>,
},
SIsMember {
key: Vec<u8>,
member: Vec<u8>,
},
SCard {
key: Vec<u8>,
},
SPop {
key: Vec<u8>,
count: Option<usize>,
},
SRandMember {
key: Vec<u8>,
count: Option<i64>,
},
SUnion {
keys: Vec<Vec<u8>>,
},
SUnionStore {
destination: Vec<u8>,
keys: Vec<Vec<u8>>,
},
SInter {
keys: Vec<Vec<u8>>,
},
SInterStore {
destination: Vec<u8>,
keys: Vec<Vec<u8>>,
},
SDiff {
keys: Vec<Vec<u8>>,
},
SDiffStore {
destination: Vec<u8>,
keys: Vec<Vec<u8>>,
},
SInterCard {
numkeys: usize,
keys: Vec<Vec<u8>>,
limit: Option<usize>,
},
SMove {
source: Vec<u8>,
destination: Vec<u8>,
member: Vec<u8>,
},
SMisMember {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
SScan {
key: Vec<u8>,
cursor: u64,
pattern: Option<String>,
count: Option<usize>,
},
Ping {
message: Option<Vec<u8>>,
},
Echo {
message: Vec<u8>,
},
Info {
section: Option<String>,
},
BgSave,
BgRewriteAof,
FlushAll,
CommandInfo {
names: Vec<Vec<u8>>,
},
Hello {
version: Option<u8>,
},
Auth {
password: Vec<u8>,
},
Dump,
Multi,
Exec,
Discard,
Watch {
keys: Vec<Vec<u8>>,
},
Unwatch,
ConfigGet {
pattern: String,
},
ConfigSet {
parameter: String,
value: String,
},
ConfigResetStat,
ClientId,
ClientGetName,
ClientSetName {
name: Vec<u8>,
},
ClientList,
ClientInfo,
Time,
Select {
db: i64,
},
Quit,
Wait {
numreplicas: i64,
timeout: i64,
},
CommandCount,
CommandList,
CommandHelp,
CommandDocs {
names: Vec<Vec<u8>>,
},
DocCreate {
collection: Vec<u8>,
compression: Option<Vec<u8>>,
},
DocDrop {
collection: Vec<u8>,
},
DocInfo {
collection: Vec<u8>,
},
DocDictInfo {
collection: Vec<u8>,
},
DocStorage {
collection: Vec<u8>,
},
DocSet {
collection: Vec<u8>,
doc_id: Vec<u8>,
json: Vec<u8>,
},
DocInsert {
collection: Vec<u8>,
json: Vec<u8>,
},
DocMSet {
collection: Vec<u8>,
entries: Vec<(Vec<u8>, Vec<u8>)>,
},
DocGet {
collection: Vec<u8>,
doc_id: Vec<u8>,
fields: Vec<Vec<u8>>,
},
DocMGet {
collection: Vec<u8>,
doc_ids: Vec<Vec<u8>>,
},
DocUpdate {
collection: Vec<u8>,
doc_id: Vec<u8>,
mutations: Vec<DocUpdateMutation>,
},
DocDel {
collection: Vec<u8>,
doc_id: Vec<u8>,
},
DocExists {
collection: Vec<u8>,
doc_id: Vec<u8>,
},
DocCreateIndex {
collection: Vec<u8>,
field: Vec<u8>,
index_type: Vec<u8>,
},
DocDropIndex {
collection: Vec<u8>,
field: Vec<u8>,
},
DocIndexes {
collection: Vec<u8>,
},
DocFind {
collection: Vec<u8>,
where_clause: Vec<u8>,
fields: Vec<Vec<u8>>,
limit: Option<usize>,
offset: usize,
order_by: Option<Vec<u8>>,
order_desc: bool,
},
DocCount {
collection: Vec<u8>,
where_clause: Vec<u8>,
},
CdcPoll {
cursor: u64,
count: usize,
},
CdcGroupCreate {
key: Vec<u8>,
group: String,
start_seq: u64,
},
CdcGroupRead {
key: Vec<u8>,
group: String,
consumer: String,
count: usize,
},
CdcAck {
key: Vec<u8>,
group: String,
seqs: Vec<u64>,
},
CdcPending {
key: Vec<u8>,
group: String,
},
VecSet {
key: Vec<u8>,
dimensions: usize,
vector: Vec<f32>,
},
VecQuery {
key: Vec<u8>,
k: usize,
vector: Vec<f32>,
},
VecDel {
key: Vec<u8>,
},
ZAdd {
key: Vec<u8>,
members: Vec<(f64, Vec<u8>)>,
},
ZRem {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
ZScore {
key: Vec<u8>,
member: Vec<u8>,
},
ZRank {
key: Vec<u8>,
member: Vec<u8>,
},
ZRevRank {
key: Vec<u8>,
member: Vec<u8>,
},
ZCard {
key: Vec<u8>,
},
ZRange {
key: Vec<u8>,
start: i64,
stop: i64,
withscores: bool,
},
ZRevRange {
key: Vec<u8>,
start: i64,
stop: i64,
withscores: bool,
},
ZRangeByScore {
key: Vec<u8>,
min: f64,
max: f64,
withscores: bool,
offset: Option<usize>,
count: Option<usize>,
},
ZIncrBy {
key: Vec<u8>,
delta: f64,
member: Vec<u8>,
},
ZCount {
key: Vec<u8>,
min: f64,
max: f64,
},
ZRevRangeByScore {
key: Vec<u8>,
max: f64,
min: f64,
withscores: bool,
offset: Option<usize>,
count: Option<usize>,
},
ZPopMin {
key: Vec<u8>,
count: Option<usize>,
},
ZPopMax {
key: Vec<u8>,
count: Option<usize>,
},
ZRangeByLex {
key: Vec<u8>,
min: Vec<u8>,
max: Vec<u8>,
offset: Option<usize>,
count: Option<usize>,
},
ZRevRangeByLex {
key: Vec<u8>,
max: Vec<u8>,
min: Vec<u8>,
offset: Option<usize>,
count: Option<usize>,
},
ZLexCount {
key: Vec<u8>,
min: Vec<u8>,
max: Vec<u8>,
},
ZMScore {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
ZRandMember {
key: Vec<u8>,
count: Option<i64>,
withscores: bool,
},
ZScan {
key: Vec<u8>,
cursor: u64,
pattern: Option<String>,
count: Option<usize>,
},
XAdd {
key: Vec<u8>,
id: Vec<u8>,
fields: Vec<(Vec<u8>, Vec<u8>)>,
maxlen: Option<usize>,
},
XLen {
key: Vec<u8>,
},
XRange {
key: Vec<u8>,
start: Vec<u8>,
end: Vec<u8>,
count: Option<usize>,
},
XRevRange {
key: Vec<u8>,
start: Vec<u8>,
end: Vec<u8>,
count: Option<usize>,
},
XRead {
keys: Vec<Vec<u8>>,
ids: Vec<Vec<u8>>,
count: Option<usize>,
},
XTrim {
key: Vec<u8>,
maxlen: usize,
},
ObjectFreq {
key: Vec<u8>,
},
ObjectEncoding {
key: Vec<u8>,
},
StatsHotkeys {
count: usize,
},
StatsLatency {
command: Vec<u8>,
percentiles: Vec<f64>,
},
StatsMemory {
prefixes: Vec<Vec<u8>>,
},
Subscribe {
channels: Vec<Vec<u8>>,
},
Unsubscribe {
channels: Vec<Vec<u8>>,
},
PSubscribe {
patterns: Vec<Vec<u8>>,
},
PUnsubscribe {
patterns: Vec<Vec<u8>>,
},
Publish {
channel: Vec<u8>,
message: Vec<u8>,
},
PfAdd {
key: Vec<u8>,
elements: Vec<Vec<u8>>,
},
PfCount {
keys: Vec<Vec<u8>>,
},
PfMerge {
destkey: Vec<u8>,
sourcekeys: Vec<Vec<u8>>,
},
SetBit {
key: Vec<u8>,
offset: u64,
value: u8,
},
GetBit {
key: Vec<u8>,
offset: u64,
},
BitCount {
key: Vec<u8>,
start: Option<i64>,
end: Option<i64>,
use_bit: bool,
},
BitOp {
operation: BitOperation,
destkey: Vec<u8>,
keys: Vec<Vec<u8>>,
},
BitPos {
key: Vec<u8>,
bit: u8,
start: Option<i64>,
end: Option<i64>,
use_bit: bool,
},
BitField {
key: Vec<u8>,
operations: Vec<BitFieldOperation>,
},
GeoAdd {
key: Vec<u8>,
nx: bool,
xx: bool,
ch: bool,
members: Vec<(f64, f64, Vec<u8>)>,
},
GeoDist {
key: Vec<u8>,
member1: Vec<u8>,
member2: Vec<u8>,
unit: GeoUnit,
},
GeoHash {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
GeoPos {
key: Vec<u8>,
members: Vec<Vec<u8>>,
},
GeoSearch {
key: Vec<u8>,
from_member: Option<Vec<u8>>,
from_lonlat: Option<(f64, f64)>,
radius: f64,
unit: GeoUnit,
asc: Option<bool>,
count: Option<usize>,
withcoord: bool,
withdist: bool,
withhash: bool,
},
BLPop {
keys: Vec<Vec<u8>>,
timeout: f64,
},
BRPop {
keys: Vec<Vec<u8>>,
timeout: f64,
},
BLMove {
source: Vec<u8>,
destination: Vec<u8>,
from_left: bool,
to_left: bool,
timeout: f64,
},
BZPopMin {
keys: Vec<Vec<u8>>,
timeout: f64,
},
BZPopMax {
keys: Vec<Vec<u8>>,
timeout: f64,
},
XGroupCreate {
key: Vec<u8>,
group: String,
id: String,
mkstream: bool,
},
XGroupDestroy {
key: Vec<u8>,
group: String,
},
XGroupDelConsumer {
key: Vec<u8>,
group: String,
consumer: String,
},
XReadGroup {
group: String,
consumer: String,
count: Option<usize>,
keys: Vec<Vec<u8>>,
ids: Vec<Vec<u8>>,
},
XAck {
key: Vec<u8>,
group: String,
ids: Vec<Vec<u8>>,
},
XPending {
key: Vec<u8>,
group: String,
start: Option<Vec<u8>>,
end: Option<Vec<u8>>,
count: Option<usize>,
},
XClaim {
key: Vec<u8>,
group: String,
consumer: String,
min_idle_time: u64,
ids: Vec<Vec<u8>>,
},
XAutoClaim {
key: Vec<u8>,
group: String,
consumer: String,
min_idle_time: u64,
start: Vec<u8>,
count: Option<usize>,
},
XInfoStream {
key: Vec<u8>,
},
XInfoGroups {
key: Vec<u8>,
},
XDel {
key: Vec<u8>,
ids: Vec<Vec<u8>>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum DocUpdateMutation {
Set {
path: Vec<u8>,
value: Vec<u8>,
},
Del {
path: Vec<u8>,
},
Incr {
path: Vec<u8>,
delta: f64,
},
Push {
path: Vec<u8>,
value: Vec<u8>,
},
Pull {
path: Vec<u8>,
value: Vec<u8>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitOperation {
And,
Or,
Xor,
Not,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BitFieldEncoding {
pub signed: bool,
pub bits: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitFieldOffset {
Absolute(i64),
Multiplied(i64),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitFieldOverflow {
Wrap,
Sat,
Fail,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitFieldOperation {
Get {
encoding: BitFieldEncoding,
offset: BitFieldOffset,
},
Set {
encoding: BitFieldEncoding,
offset: BitFieldOffset,
value: i64,
},
IncrBy {
encoding: BitFieldEncoding,
offset: BitFieldOffset,
increment: i64,
},
Overflow(BitFieldOverflow),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GeoUnit {
Meters,
Kilometers,
Feet,
Miles,
}
impl Command {
pub fn key(&self) -> Option<&[u8]> {
match self {
Command::Get { key }
| Command::Set { key, .. }
| Command::GetSet { key, .. }
| Command::Append { key, .. }
| Command::Strlen { key }
| Command::Incr { key }
| Command::Decr { key }
| Command::IncrBy { key, .. }
| Command::DecrBy { key, .. }
| Command::SetNx { key, .. }
| Command::Expire { key, .. }
| Command::PExpire { key, .. }
| Command::Persist { key }
| Command::Ttl { key }
| Command::PTtl { key }
| Command::Type { key }
| Command::LPush { key, .. }
| Command::RPush { key, .. }
| Command::LPop { key }
| Command::RPop { key }
| Command::LLen { key }
| Command::LRange { key, .. }
| Command::LIndex { key, .. }
| Command::LSet { key, .. }
| Command::LInsert { key, .. }
| Command::LRem { key, .. }
| Command::LTrim { key, .. }
| Command::LPos { key, .. }
| Command::RPopLPush { source: key, .. }
| Command::LMove { source: key, .. }
| Command::HSet { key, .. }
| Command::HGet { key, .. }
| Command::HDel { key, .. }
| Command::HGetAll { key }
| Command::HLen { key }
| Command::HExists { key, .. }
| Command::HIncrBy { key, .. }
| Command::HMGet { key, .. }
| Command::HKeys { key }
| Command::HVals { key }
| Command::HSetNx { key, .. }
| Command::HIncrByFloat { key, .. }
| Command::HRandField { key, .. }
| Command::HScan { key, .. }
| Command::SAdd { key, .. }
| Command::SRem { key, .. }
| Command::SMembers { key }
| Command::SIsMember { key, .. }
| Command::SCard { key }
| Command::SPop { key, .. }
| Command::SRandMember { key, .. }
| Command::SMove { source: key, .. }
| Command::SMisMember { key, .. }
| Command::SScan { key, .. }
| Command::ZAdd { key, .. }
| Command::ZRem { key, .. }
| Command::ZScore { key, .. }
| Command::ZRank { key, .. }
| Command::ZRevRank { key, .. }
| Command::ZCard { key }
| Command::ZRange { key, .. }
| Command::ZRevRange { key, .. }
| Command::ZRangeByScore { key, .. }
| Command::ZIncrBy { key, .. }
| Command::ZCount { key, .. }
| Command::ZRevRangeByScore { key, .. }
| Command::ZPopMin { key, .. }
| Command::ZPopMax { key, .. }
| Command::ZRangeByLex { key, .. }
| Command::ZRevRangeByLex { key, .. }
| Command::ZLexCount { key, .. }
| Command::ZMScore { key, .. }
| Command::ZRandMember { key, .. }
| Command::ZScan { key, .. }
| Command::VecSet { key, .. }
| Command::VecDel { key }
| Command::XAdd { key, .. }
| Command::XLen { key }
| Command::XRange { key, .. }
| Command::XRevRange { key, .. }
| Command::XTrim { key, .. }
| Command::ObjectFreq { key }
| Command::ObjectEncoding { key }
| Command::ObjectRefCount { key }
| Command::ObjectIdleTime { key }
| Command::IncrByFloat { key, .. }
| Command::GetRange { key, .. }
| Command::SetRange { key, .. }
| Command::GetDel { key }
| Command::GetEx { key, .. }
| Command::ExpireAt { key, .. }
| Command::PExpireAt { key, .. }
| Command::Rename { key, .. }
| Command::RenameNx { key, .. }
| Command::Copy { source: key, .. }
| Command::PfAdd { key, .. }
| Command::SetBit { key, .. }
| Command::GetBit { key, .. }
| Command::BitCount { key, .. }
| Command::BitPos { key, .. }
| Command::BitField { key, .. }
| Command::GeoAdd { key, .. }
| Command::GeoDist { key, .. }
| Command::GeoHash { key, .. }
| Command::GeoPos { key, .. }
| Command::GeoSearch { key, .. }
| Command::BLMove { source: key, .. }
| Command::XGroupCreate { key, .. }
| Command::XGroupDestroy { key, .. }
| Command::XGroupDelConsumer { key, .. }
| Command::XAck { key, .. }
| Command::XPending { key, .. }
| Command::XClaim { key, .. }
| Command::XAutoClaim { key, .. }
| Command::XInfoStream { key }
| Command::XInfoGroups { key }
| Command::XDel { key, .. } => Some(key),
Command::PfCount { keys } => {
if keys.len() == 1 {
Some(&keys[0])
} else {
None
}
}
Command::VecQuery { .. } => None,
_ => None,
}
}
pub fn is_multi_key(&self) -> bool {
matches!(
self,
Command::MGet { .. }
| Command::MSet { .. }
| Command::Del { .. }
| Command::Exists { .. }
| Command::XRead { .. }
| Command::MSetNx { .. }
| Command::Unlink { .. }
| Command::Touch { .. }
| Command::SUnion { .. }
| Command::SUnionStore { .. }
| Command::SInter { .. }
| Command::SInterStore { .. }
| Command::SDiff { .. }
| Command::SDiffStore { .. }
| Command::SInterCard { .. }
| Command::PfMerge { .. }
| Command::BitOp { .. }
| Command::BLPop { .. }
| Command::BRPop { .. }
| Command::BZPopMin { .. }
| Command::BZPopMax { .. }
| Command::XReadGroup { .. }
) || matches!(self, Command::PfCount { keys } if keys.len() > 1)
}
pub fn is_keyless(&self) -> bool {
matches!(
self,
Command::Ping { .. }
| Command::Echo { .. }
| Command::Info { .. }
| Command::DbSize
| Command::FlushDb
| Command::FlushAll
| Command::Keys { .. }
| Command::Scan { .. }
| Command::BgSave
| Command::BgRewriteAof
| Command::CommandInfo { .. }
| Command::Hello { .. }
| Command::Auth { .. }
| Command::Dump
| Command::CdcPoll { .. }
| Command::CdcGroupCreate { .. }
| Command::CdcGroupRead { .. }
| Command::CdcAck { .. }
| Command::CdcPending { .. }
| Command::StatsHotkeys { .. }
| Command::StatsLatency { .. }
| Command::StatsMemory { .. }
| Command::Subscribe { .. }
| Command::Unsubscribe { .. }
| Command::PSubscribe { .. }
| Command::PUnsubscribe { .. }
| Command::Publish { .. }
| Command::RandomKey
| Command::ObjectHelp
| Command::Multi
| Command::Exec
| Command::Discard
| Command::Watch { .. }
| Command::Unwatch
| Command::ConfigGet { .. }
| Command::ConfigSet { .. }
| Command::ConfigResetStat
| Command::ClientId
| Command::ClientGetName
| Command::ClientSetName { .. }
| Command::ClientList
| Command::ClientInfo
| Command::Time
| Command::Select { .. }
| Command::Quit
| Command::Wait { .. }
| Command::CommandCount
| Command::CommandList
| Command::CommandHelp
| Command::CommandDocs { .. }
| Command::DocCreate { .. }
| Command::DocDrop { .. }
| Command::DocInfo { .. }
| Command::DocDictInfo { .. }
| Command::DocStorage { .. }
| Command::DocSet { .. }
| Command::DocInsert { .. }
| Command::DocMSet { .. }
| Command::DocGet { .. }
| Command::DocMGet { .. }
| Command::DocUpdate { .. }
| Command::DocDel { .. }
| Command::DocExists { .. }
| Command::DocCreateIndex { .. }
| Command::DocDropIndex { .. }
| Command::DocIndexes { .. }
| Command::DocFind { .. }
| Command::DocCount { .. }
)
}
pub fn is_mutation(&self) -> bool {
matches!(
self,
Command::Set { .. }
| Command::GetSet { .. }
| Command::Append { .. }
| Command::Incr { .. }
| Command::Decr { .. }
| Command::IncrBy { .. }
| Command::DecrBy { .. }
| Command::MSet { .. }
| Command::SetNx { .. }
| Command::Del { .. }
| Command::Expire { .. }
| Command::PExpire { .. }
| Command::Persist { .. }
| Command::FlushDb
| Command::FlushAll
| Command::LPush { .. }
| Command::RPush { .. }
| Command::LPop { .. }
| Command::RPop { .. }
| Command::LSet { .. }
| Command::LInsert { .. }
| Command::LRem { .. }
| Command::LTrim { .. }
| Command::RPopLPush { .. }
| Command::LMove { .. }
| Command::HSet { .. }
| Command::HDel { .. }
| Command::HIncrBy { .. }
| Command::HSetNx { .. }
| Command::HIncrByFloat { .. }
| Command::SAdd { .. }
| Command::SRem { .. }
| Command::SPop { .. }
| Command::SUnionStore { .. }
| Command::SInterStore { .. }
| Command::SDiffStore { .. }
| Command::SMove { .. }
| Command::ZAdd { .. }
| Command::ZRem { .. }
| Command::ZIncrBy { .. }
| Command::ZPopMin { .. }
| Command::ZPopMax { .. }
| Command::VecSet { .. }
| Command::VecDel { .. }
| Command::XAdd { .. }
| Command::XTrim { .. }
| Command::IncrByFloat { .. }
| Command::SetRange { .. }
| Command::GetDel { .. }
| Command::GetEx { .. }
| Command::MSetNx { .. }
| Command::ExpireAt { .. }
| Command::PExpireAt { .. }
| Command::Rename { .. }
| Command::RenameNx { .. }
| Command::Unlink { .. }
| Command::Copy { .. }
| Command::PfAdd { .. }
| Command::PfMerge { .. }
| Command::SetBit { .. }
| Command::BitOp { .. }
| Command::GeoAdd { .. }
| Command::BLPop { .. }
| Command::BRPop { .. }
| Command::BLMove { .. }
| Command::BZPopMin { .. }
| Command::BZPopMax { .. }
| Command::XGroupCreate { .. }
| Command::XGroupDestroy { .. }
| Command::XGroupDelConsumer { .. }
| Command::XAck { .. }
| Command::XClaim { .. }
| Command::XAutoClaim { .. }
| Command::XDel { .. }
| Command::DocCreate { .. }
| Command::DocDrop { .. }
| Command::DocSet { .. }
| Command::DocInsert { .. }
| Command::DocMSet { .. }
| Command::DocUpdate { .. }
| Command::DocDel { .. }
| Command::DocCreateIndex { .. }
| Command::DocDropIndex { .. }
)
}
pub fn cmd_type(&self) -> u8 {
match self {
Command::Get { .. } => 0,
Command::Set { .. } => 1,
Command::Del { .. } | Command::Unlink { .. } => 2,
Command::Incr { .. } | Command::IncrBy { .. } | Command::IncrByFloat { .. } => 3,
Command::Decr { .. } | Command::DecrBy { .. } => 4,
Command::MGet { .. } => 5,
Command::MSet { .. } | Command::MSetNx { .. } => 6,
Command::Exists { .. } => 7,
Command::Expire { .. }
| Command::PExpire { .. }
| Command::ExpireAt { .. }
| Command::PExpireAt { .. } => 8,
Command::Ttl { .. } | Command::PTtl { .. } => 9,
Command::LPush { .. } => 10,
Command::RPush { .. } => 11,
Command::LPop { .. } => 12,
Command::RPop { .. } => 13,
Command::HSet { .. } | Command::HSetNx { .. } => 14,
Command::HGet { .. } | Command::HMGet { .. } => 15,
Command::HGetAll { .. } | Command::HKeys { .. } | Command::HVals { .. } => 16,
Command::SAdd { .. } => 17,
Command::SRem { .. } | Command::SPop { .. } => 18,
Command::SRandMember { .. } | Command::SMisMember { .. } | Command::SScan { .. } => 40,
Command::SUnion { .. }
| Command::SUnionStore { .. }
| Command::SInter { .. }
| Command::SInterStore { .. }
| Command::SDiff { .. }
| Command::SDiffStore { .. }
| Command::SInterCard { .. }
| Command::SMove { .. } => 41,
Command::Ping { .. } => 19,
Command::Info { .. } => 20,
Command::DbSize => 21,
Command::FlushDb | Command::FlushAll => 22,
Command::Keys { .. } | Command::Scan { .. } => 23,
Command::VecSet { .. } => 24,
Command::VecQuery { .. } => 25,
Command::ZAdd { .. } => 27,
Command::ZRange { .. }
| Command::ZRevRange { .. }
| Command::ZRangeByScore { .. }
| Command::ZRevRangeByScore { .. }
| Command::ZRangeByLex { .. }
| Command::ZRevRangeByLex { .. } => 28,
Command::ZScore { .. }
| Command::ZRank { .. }
| Command::ZRevRank { .. }
| Command::ZCard { .. }
| Command::ZCount { .. }
| Command::ZLexCount { .. }
| Command::ZMScore { .. } => 29,
Command::ZRem { .. }
| Command::ZIncrBy { .. }
| Command::ZPopMin { .. }
| Command::ZPopMax { .. } => 30,
Command::ZRandMember { .. } | Command::ZScan { .. } => 42,
Command::ObjectFreq { .. }
| Command::ObjectEncoding { .. }
| Command::ObjectRefCount { .. }
| Command::ObjectIdleTime { .. }
| Command::ObjectHelp => 31,
Command::XAdd { .. } | Command::XTrim { .. } => 33,
Command::XLen { .. }
| Command::XRange { .. }
| Command::XRevRange { .. }
| Command::XRead { .. } => 34,
Command::Subscribe { .. }
| Command::Unsubscribe { .. }
| Command::PSubscribe { .. }
| Command::PUnsubscribe { .. }
| Command::Publish { .. } => 35,
Command::LSet { .. }
| Command::LInsert { .. }
| Command::LRem { .. }
| Command::LTrim { .. } => 36,
Command::LPos { .. } => 37,
Command::RPopLPush { .. } | Command::LMove { .. } => 38,
Command::HRandField { .. } | Command::HScan { .. } => 39,
Command::PfAdd { .. } | Command::PfCount { .. } | Command::PfMerge { .. } => 43,
Command::SetBit { .. }
| Command::GetBit { .. }
| Command::BitCount { .. }
| Command::BitOp { .. }
| Command::BitPos { .. }
| Command::BitField { .. } => 44,
Command::GeoAdd { .. }
| Command::GeoDist { .. }
| Command::GeoHash { .. }
| Command::GeoPos { .. }
| Command::GeoSearch { .. } => 45,
Command::Multi
| Command::Exec
| Command::Discard
| Command::Watch { .. }
| Command::Unwatch => 46,
Command::ConfigGet { .. }
| Command::ConfigSet { .. }
| Command::ConfigResetStat
| Command::ClientId
| Command::ClientGetName
| Command::ClientSetName { .. }
| Command::ClientList
| Command::ClientInfo
| Command::Time
| Command::Select { .. }
| Command::Quit
| Command::Wait { .. }
| Command::CommandCount
| Command::CommandList
| Command::CommandHelp
| Command::CommandDocs { .. } => 47,
Command::BLPop { .. }
| Command::BRPop { .. }
| Command::BLMove { .. }
| Command::BZPopMin { .. }
| Command::BZPopMax { .. } => 48,
Command::XGroupCreate { .. }
| Command::XGroupDestroy { .. }
| Command::XGroupDelConsumer { .. }
| Command::XReadGroup { .. }
| Command::XAck { .. }
| Command::XPending { .. }
| Command::XClaim { .. }
| Command::XAutoClaim { .. }
| Command::XInfoStream { .. }
| Command::XInfoGroups { .. }
| Command::XDel { .. } => 49,
Command::DocCreate { .. }
| Command::DocDrop { .. }
| Command::DocInfo { .. }
| Command::DocDictInfo { .. }
| Command::DocStorage { .. }
| Command::DocSet { .. }
| Command::DocInsert { .. }
| Command::DocMSet { .. }
| Command::DocGet { .. }
| Command::DocMGet { .. }
| Command::DocUpdate { .. }
| Command::DocDel { .. }
| Command::DocExists { .. }
| Command::DocCreateIndex { .. }
| Command::DocDropIndex { .. }
| Command::DocIndexes { .. }
| Command::DocFind { .. }
| Command::DocCount { .. } => 50,
_ => 32,
}
}
pub fn ttl_duration(ex: Option<u64>, px: Option<u64>) -> Option<Duration> {
if let Some(s) = ex {
Some(Duration::from_secs(s))
} else {
px.map(Duration::from_millis)
}
}
}
pub const SUPPORTED_COMMAND_NAMES: &[&str] = &[
"append",
"auth",
"bgrewriteaof",
"bgsave",
"bitcount",
"bitfield",
"bitop",
"bitpos",
"blmove",
"blpop",
"brpop",
"bzpopmax",
"bzpopmin",
"cdc.ack",
"cdc.group",
"cdc.pending",
"cdcpoll",
"client",
"command",
"config",
"copy",
"dbsize",
"decr",
"decrby",
"del",
"discard",
"doc.count",
"doc.create",
"doc.createindex",
"doc.del",
"doc.dictinfo",
"doc.drop",
"doc.dropindex",
"doc.exists",
"doc.find",
"doc.get",
"doc.indexes",
"doc.info",
"doc.mget",
"doc.mset",
"doc.set",
"doc.storage",
"doc.update",
"dump",
"echo",
"exec",
"exists",
"expire",
"expireat",
"flushall",
"flushdb",
"geoadd",
"geodist",
"geohash",
"geopos",
"geosearch",
"get",
"getbit",
"getdel",
"getex",
"getrange",
"getset",
"hdel",
"hello",
"hexists",
"hget",
"hgetall",
"hincrby",
"hincrbyfloat",
"hkeys",
"hlen",
"hmget",
"hmset",
"hrandfield",
"hscan",
"hset",
"hsetnx",
"hvals",
"incr",
"incrby",
"incrbyfloat",
"info",
"keys",
"lindex",
"linsert",
"llen",
"lmove",
"lpop",
"lpos",
"lpush",
"lrange",
"lrem",
"lset",
"ltrim",
"mget",
"mset",
"msetnx",
"multi",
"object",
"persist",
"pexpire",
"pexpireat",
"pfadd",
"pfcount",
"pfmerge",
"ping",
"psetex",
"psubscribe",
"pttl",
"publish",
"punsubscribe",
"quit",
"randomkey",
"rename",
"renamenx",
"rpop",
"rpoplpush",
"rpush",
"sadd",
"scan",
"scard",
"sdiff",
"sdiffstore",
"select",
"set",
"setbit",
"setex",
"setnx",
"setrange",
"sinter",
"sintercard",
"sinterstore",
"sismember",
"smembers",
"smismember",
"smove",
"spop",
"srandmember",
"srem",
"sscan",
"stats.hotkeys",
"stats.latency",
"stats.memory",
"strlen",
"subscribe",
"substr",
"sunion",
"sunionstore",
"time",
"touch",
"ttl",
"type",
"unlink",
"unsubscribe",
"unwatch",
"vecdel",
"vecquery",
"vecset",
"wait",
"watch",
"xack",
"xadd",
"xautoclaim",
"xclaim",
"xdel",
"xgroup",
"xinfo",
"xlen",
"xpending",
"xrange",
"xread",
"xreadgroup",
"xrevrange",
"xtrim",
"zadd",
"zcard",
"zcount",
"zincrby",
"zlexcount",
"zmscore",
"zpopmax",
"zpopmin",
"zrandmember",
"zrange",
"zrangebylex",
"zrangebyscore",
"zrank",
"zrem",
"zrevrange",
"zrevrangebylex",
"zrevrangebyscore",
"zrevrank",
"zscan",
"zscore",
];
pub const COMMAND_HELP_LINES: &[&str] = &[
"COMMAND <subcommand> [<arg> [value] [opt] ...]. Subcommands are:",
"(no subcommand)",
" Return details about all Kora commands.",
"COUNT",
" Return the total number of commands in this Kora server.",
"LIST",
" Return a list of all commands in this Kora server.",
"INFO [<command-name> ...]",
" Return details about multiple Kora commands.",
"DOCS [<command-name> ...]",
" Return documentation details about multiple Kora commands.",
"HELP",
" Print this help.",
];
pub fn supported_command_count() -> i64 {
SUPPORTED_COMMAND_NAMES.len() as i64
}
fn normalize_command_name(name: &[u8]) -> String {
String::from_utf8_lossy(name).to_ascii_lowercase()
}
fn command_supported(name: &str) -> bool {
SUPPORTED_COMMAND_NAMES.binary_search(&name).is_ok()
}
fn command_info_entry(name: &str) -> CommandResponse {
CommandResponse::Array(vec![
CommandResponse::BulkString(name.as_bytes().to_vec()),
CommandResponse::Integer(-1),
CommandResponse::Array(vec![CommandResponse::BulkString(b"fast".to_vec())]),
CommandResponse::Integer(0),
CommandResponse::Integer(0),
CommandResponse::Integer(0),
CommandResponse::Array(vec![CommandResponse::BulkString(b"@kora".to_vec())]),
CommandResponse::Array(vec![]),
CommandResponse::Array(vec![]),
CommandResponse::Array(vec![]),
])
}
pub fn command_info_response(names: &[Vec<u8>]) -> CommandResponse {
if names.is_empty() {
return CommandResponse::Array(
SUPPORTED_COMMAND_NAMES
.iter()
.map(|name| command_info_entry(name))
.collect(),
);
}
let mut entries = Vec::with_capacity(names.len());
for name in names {
let normalized = normalize_command_name(name);
if command_supported(&normalized) {
entries.push(command_info_entry(&normalized));
} else {
entries.push(CommandResponse::Nil);
}
}
CommandResponse::Array(entries)
}
pub fn command_list_response() -> CommandResponse {
CommandResponse::Array(
SUPPORTED_COMMAND_NAMES
.iter()
.map(|name| CommandResponse::BulkString(name.as_bytes().to_vec()))
.collect(),
)
}
fn command_docs_entry(name: &str) -> CommandResponse {
CommandResponse::Map(vec![
(
CommandResponse::BulkString(b"summary".to_vec()),
CommandResponse::BulkString(format!("Kora implementation of `{}`.", name).into_bytes()),
),
(
CommandResponse::BulkString(b"since".to_vec()),
CommandResponse::BulkString(b"0.1.0".to_vec()),
),
(
CommandResponse::BulkString(b"group".to_vec()),
CommandResponse::BulkString(b"generic".to_vec()),
),
])
}
pub fn command_docs_response(names: &[Vec<u8>]) -> CommandResponse {
let mut docs = Vec::new();
if names.is_empty() {
docs.reserve(SUPPORTED_COMMAND_NAMES.len());
for name in SUPPORTED_COMMAND_NAMES {
docs.push((
CommandResponse::BulkString(name.as_bytes().to_vec()),
command_docs_entry(name),
));
}
return CommandResponse::Map(docs);
}
for name in names {
let normalized = normalize_command_name(name);
if command_supported(&normalized) {
docs.push((
CommandResponse::BulkString(normalized.as_bytes().to_vec()),
command_docs_entry(&normalized),
));
}
}
CommandResponse::Map(docs)
}
pub fn command_help_response() -> CommandResponse {
CommandResponse::Array(
COMMAND_HELP_LINES
.iter()
.map(|line| CommandResponse::BulkString(line.as_bytes().to_vec()))
.collect(),
)
}
#[derive(Debug, Clone, PartialEq)]
pub enum CommandResponse {
Ok,
Nil,
Integer(i64),
BulkString(Vec<u8>),
BulkStringShared(Arc<[u8]>),
SimpleString(String),
Array(Vec<CommandResponse>),
Error(String),
Map(Vec<(CommandResponse, CommandResponse)>),
Set(Vec<CommandResponse>),
Double(f64),
Boolean(bool),
}
impl CommandResponse {
pub fn bulk_string_bytes(&self) -> Option<&[u8]> {
match self {
CommandResponse::BulkString(data) => Some(data),
CommandResponse::BulkStringShared(data) => Some(data),
_ => None,
}
}
pub fn into_bulk_string_bytes(self) -> Option<Vec<u8>> {
match self {
CommandResponse::BulkString(data) => Some(data),
CommandResponse::BulkStringShared(data) => Some(data.as_ref().to_vec()),
_ => None,
}
}
}