redis_regular_expression_module/
lib.rs

1use crate::args::GetRegularExpression;
2use redis_module::{Context, RedisError, RedisResult, RedisString, RedisValue, Status, redis_command, redis_module};
3use std::convert::TryFrom;
4
5pub mod args;
6
7const REDIS_COMMAND_KEYS: &'static str = "KEYS";
8const REDIS_PATTERN_KEY_ALL: &'static str = "*";
9
10const RG_KEYS: &'static str = "rgkeys";
11const RG_VALUES: &'static str = "rgvalues";
12const RG_DELETE: &'static str = "rgdelete";
13
14const READ_ONLY: &'static str = "readonly";
15const WRITE: &'static str = "write";
16
17fn handle_redis_command_result(result: Vec<RedisValue>) -> impl Iterator<Item = String> {
18    result
19        .into_iter()
20        .map(|value| match value {
21            RedisValue::SimpleString(value) => Some(value),
22            _ => None,
23        })
24        .filter(|value| value.is_some())
25        .map(|value| value.unwrap())
26}
27
28fn find_keys_by_rg(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
29    ctx.log_debug(&format!("Run {}", RG_KEYS));
30
31    let args = crate::args::FindByKey::try_from(args)?;
32
33    let command_result = ctx.call(REDIS_COMMAND_KEYS, &[REDIS_PATTERN_KEY_ALL])?;
34
35    let command_result = match command_result {
36        RedisValue::Array(data) => Ok(data),
37        _ => Err(RedisError::Str(
38            "Wrong return result from `KEYS` command, expected array.",
39        )),
40    }?;
41
42    ctx.log_debug(&format!("{:?}", command_result));
43
44    let result: Vec<RedisValue> = handle_redis_command_result(command_result)
45        .filter(move |s| args.get_regular_expression().is_match(&s.to_string()))
46        .map(move |s| RedisValue::SimpleString(s))
47        .collect();
48
49    Ok(RedisValue::Array(result))
50}
51
52fn find_values_by_rg(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
53    ctx.log_debug(&format!("Run {}", RG_VALUES));
54
55    let args = crate::args::FindByValue::try_from(args)?;
56
57    let command_keys_result = ctx.call(
58        REDIS_COMMAND_KEYS,
59        &[args.get_redis_mask()]
60    )?;
61
62    let result_keys_command = match command_keys_result {
63        RedisValue::Array(data) => Ok(data),
64        _ => Err(RedisError::Str(
65            "Wrong return result from `MGET` command, expected array.",
66        )),
67    }?;
68
69    let result_redis_value: Vec<RedisValue> = handle_redis_command_result(result_keys_command)
70        .map(move |key| {
71            let redis_key = ctx.open_key(&ctx.create_string(&key));
72            match redis_key.read() {
73                Ok(value) => (Some(key), value),
74                Err(e) => {
75                    ctx.log_debug(&format!("{}", e));
76                    (None, None)
77                }
78            }
79        })
80        .filter(|(key, value)| value.is_some() && key.is_some())
81        .map(|(key, value)| (key.unwrap(), value.unwrap()))
82        .filter(move |(_, value)| args.get_regular_expression().is_match(&value))
83        .map(|(key, _)| RedisValue::SimpleString(key))
84        .collect();
85
86    Ok(RedisValue::Array(result_redis_value))
87}
88
89fn delete_keys_by_rg(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
90    ctx.log_debug(&format!("Run {}", RG_DELETE));
91
92    let args = crate::args::FindByKey::try_from(args)?;
93    let raw_regular_expression = format!("{}", args.get_regular_expression());
94
95    let command_result = ctx.call(RG_KEYS, &[&raw_regular_expression])?;
96
97    let result = match command_result {
98        RedisValue::Array(data) => Ok(data),
99        RedisValue::NoReply => {
100            return Ok(RedisValue::NoReply);
101        }
102        _ => Err(RedisError::Str(
103            "Wrong return result from `KEYS` command, expected array.",
104        )),
105    }?;
106
107    let count_delete_redis_key: u64 = handle_redis_command_result(result)
108        .map(move |key| {
109            let redis_key = ctx.open_key_writable(&ctx.create_string(&key));
110            redis_key.delete()
111        })
112        .fold(0, |acc, data| if data.is_ok() {acc + 1} else {acc});
113
114    Ok(RedisValue::Integer(count_delete_redis_key as i64))
115}
116
117redis_module! {
118    name: "RustRegxCommand",
119    version: 0.5,
120    data_types: [],
121    init: init,
122    deinit: deinit,
123    commands: [
124        [RG_KEYS, find_keys_by_rg, READ_ONLY, 1, 1, 1],
125        [RG_VALUES, find_values_by_rg, READ_ONLY, 1, 1, 1],
126        [RG_DELETE, delete_keys_by_rg, WRITE, 1, 1, 1],
127    ]
128}
129
130fn init(ctx: &Context, _args: &Vec<RedisString>) -> Status {
131    ctx.log_debug("Start");
132
133    Status::Ok
134}
135
136fn deinit(ctx: &Context) -> Status {
137    ctx.log_debug("End");
138
139    Status::Ok
140}