import { Command } from "https://deno.land/x/cliffy@v0.25.5/command/mod.ts"; import { connect } from "https://deno.land/x/redis@v0.27.4/mod.ts"; import { TerminalSpinner } from "https://deno.land/x/spinners@v1.1.2/mod.ts"; await new Command() .name("redis-pattern-cmd") .description("A simple Redis pattern command executor") .version("v1.0.0") .option("--redis-port ", "Port for Redis server.", { default: 6379, }) .option("--redis-host ", "The host name for the Redis server.", { default: "localhost", }) .option("--page-count ", "Number of items per page when doing scan", { default: 1000, }) .option("--command-params ", "Extra space separated parameters to pass for redis commands", { default: [], separator: " ", }) .arguments("[command:string] [pattern:string] [params...]") .example("Delete everything matching a pattern", "DEL foo:*") .example("Set TTL of all keys matching pattern with no expiry", `--command-params "60 NX" EXPIRE foo:*`) .action(async ({ redisHost, redisPort, pageCount, commandParams: params}, cmd = "TOUCH", pattern = "*") => { const redis = await connect({ hostname: redisHost, port: redisPort }); const paramsJoined = params.join(' '); const spinner = new TerminalSpinner(`Processing...`); let page = 0; main_loop: do { const [nextPage, scannedKeys] = await redis.scan(page, {pattern, count: pageCount}); for(const k of scannedKeys) { spinner.set(`${cmd} ${k.slice(0, 32)} ${paramsJoined} `); try { await redis.sendCommand(cmd, k, ...params); spinner.renderNextFrame(); } catch (e) { spinner.fail(`Error: ${e}`); break main_loop; } } page = parseInt(nextPage); if (page === 0) { spinner.succeed("Completed!"); } } while (page !== 0); }) .parse(Deno.args);