packages feed

hask-redis-mux-0.1.0.0: lib/cluster/Database/Redis/Cluster/Commands.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Shared command classification for cluster routing
-- This module provides lists of Redis commands categorized by their routing requirements
--
-- @since 0.1.0.0
module Database.Redis.Cluster.Commands
  ( keylessCommands,
    requiresKeyCommands,
    CommandRouting (..),
    classifyCommand,
  )
where

import           Data.ByteString       (ByteString)
import qualified Data.ByteString.Char8 as BS8
import           Data.Char             (toUpper)

-- | Result of classifying a command for cluster routing
data CommandRouting
  = KeylessRoute        -- ^ Route to any master node
  | KeyedRoute ByteString  -- ^ Route by this key's hash slot
  | CommandError String    -- ^ Invalid command (e.g., missing required key)

-- | Classify a Redis command for cluster routing.
-- Returns 'KeylessRoute' for commands like PING or AUTH that can go to any master,
-- 'KeyedRoute' with the routing key for commands that target a specific slot,
-- or 'CommandError' if a key-requiring command is missing its key argument.
classifyCommand :: ByteString -> [ByteString] -> CommandRouting
classifyCommand cmd args =
  let cmdUpper = BS8.map toUpper cmd
  in if cmdUpper `elem` keylessCommands
     then KeylessRoute
     else case args of
       [] -> if cmdUpper `elem` requiresKeyCommands
               then CommandError $ "Command " ++ BS8.unpack cmd ++ " requires a key argument"
               else KeylessRoute  -- Unknown command without args, try keyless
       (key:_) -> KeyedRoute key

-- | Commands that don't require a key argument (route to any master node)
-- These commands can be executed on any master node in the cluster
-- Note: This list is based on Redis 7.x commands and may need updates for newer versions
-- See CLUSTERING_IMPLEMENTATION_PLAN.md Phase 17 for future work on eliminating this hardcoded list
keylessCommands :: [ByteString]
keylessCommands =
  [ "PING",
    "AUTH",
    "FLUSHALL",
    "FLUSHDB",
    "DBSIZE",
    "CLUSTER",
    "INFO",
    "TIME",
    "CLIENT",
    "CONFIG",
    "BGREWRITEAOF",
    "BGSAVE",
    "SAVE",
    "LASTSAVE",
    "SHUTDOWN",
    "SLAVEOF",
    "REPLICAOF",
    "ROLE",
    "ECHO",
    "SELECT",
    "QUIT",
    "COMMAND"
  ]

-- | Commands that require a key argument (route by key's hash slot)
-- These commands must be routed to the node responsible for the key's hash slot
-- Note: This list is based on Redis 7.x commands and may need updates for newer versions
-- See CLUSTERING_IMPLEMENTATION_PLAN.md Phase 17 for future work on eliminating this hardcoded list
requiresKeyCommands :: [ByteString]
requiresKeyCommands =
  [ "GET",
    "SET",
    "DEL",
    "EXISTS",
    "INCR",
    "DECR",
    "HGET",
    "HSET",
    "HDEL",
    "HKEYS",
    "HVALS",
    "HGETALL",
    "HEXISTS",
    "LPUSH",
    "RPUSH",
    "LPOP",
    "RPOP",
    "LRANGE",
    "LLEN",
    "LINDEX",
    "SADD",
    "SREM",
    "SMEMBERS",
    "SCARD",
    "SISMEMBER",
    "ZADD",
    "ZREM",
    "ZRANGE",
    "ZCARD",
    "EXPIRE",
    "TTL",
    "PERSIST",
    "MGET",
    "MSET",
    "SETNX",
    "PSETEX",
    "APPEND",
    "GETRANGE",
    "SETRANGE",
    "STRLEN",
    "GETEX",
    "GETDEL",
    "SETEX"
  ]