-
Notifications
You must be signed in to change notification settings - Fork 0
/
storage.rs
106 lines (96 loc) · 3.27 KB
/
storage.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use crate::BotResult;
use redis::Commands;
use std::{ops::DerefMut, sync::Mutex};
pub type StorageResult<'s, T> = Result<T, Box<dyn std::error::Error + 's>>;
pub struct Storage {
redis: Mutex<redis::Connection>,
}
impl Storage {
pub fn new(redis_url: &str) -> BotResult<Self> {
let redis = redis::Client::open(redis_url)
.and_then(|c| c.get_connection())
.map_err(|e| format!("Redis: {}", e))?;
Ok(Self {
redis: Mutex::new(redis),
})
}
pub fn set_add<'s, V: redis::ToRedisArgs + std::fmt::Display + Copy>(
&'s self,
set: &str,
value: V,
) -> StorageResult<'s, ()> {
let mut conn = self.redis.lock()?;
conn.sadd(set, value)
.map_err(|e| format!("Cannot add {} to {}: {}", value, set, e).into())
}
pub fn set_contains<'s, V: redis::ToRedisArgs + std::fmt::Display + Copy>(
&'s self,
set: &str,
value: V,
) -> StorageResult<'s, bool> {
let mut conn = self.redis.lock()?;
conn.sismember(set, value)
.map_err(|e| format!("Cannot check membership of {} in {}: {}", value, set, e).into())
}
pub fn sets_add_and_count_containing<'s, V: redis::ToRedisArgs + std::fmt::Display + Copy>(
&'s self,
add_to_sets: &[String],
count_in_sets: &[String],
value: V,
) -> StorageResult<'s, usize> {
let mut pipe = redis::pipe();
pipe.atomic();
for set in add_to_sets {
pipe.sadd(set, value).ignore();
}
for set in count_in_sets {
pipe.sismember(set, value);
}
let mut conn = self.redis.lock()?;
pipe.query::<Vec<bool>>(conn.deref_mut())
.map(|r| r.iter().filter(|ismem| **ismem).count())
.map_err(|e| {
format!(
"Cannot add {} to sets {} with membership check across {}: {}",
value,
add_to_sets.join(","),
count_in_sets.join(","),
e
)
.into()
})
}
pub fn sets_len<'s, S: AsRef<str>, I: IntoIterator<Item = S>>(
&'s self,
sets: I,
) -> StorageResult<'s, Vec<u64>> {
let mut pipe = redis::pipe();
pipe.atomic();
for set in sets {
pipe.scard(set.as_ref());
}
let mut conn = self.redis.lock()?;
pipe.query::<Vec<u64>>(conn.deref_mut())
.map_err(|e| format!("Cannot lookup set cardinality: {}", e).into())
}
pub fn hash_set<'s, F: redis::ToRedisArgs + std::fmt::Display + Copy>(
&'s self,
hash: &str,
field: F,
value: u64,
) -> StorageResult<'s, i64> {
let mut conn = self.redis.lock()?;
conn.hset(hash, field, value)
.map_err(|e| format!("Cannot set {}[{}] to {}: {}", hash, field, value, e).into())
}
pub fn hash_incr<'s, F: redis::ToRedisArgs + std::fmt::Display + Copy>(
&'s self,
hash: &str,
field: F,
delta: i64,
) -> StorageResult<'s, i64> {
let mut conn = self.redis.lock()?;
conn.hincr(hash, field, delta)
.map_err(|e| format!("Cannot increment {}[{}] by {}: {}", hash, field, delta, e).into())
}
}