1use std::io;
14
15use crate::store::Store;
16
17pub struct Pipeline<'a> {
21 store: &'a Store,
22 ops: Vec<PendingOp>,
23}
24
25enum PendingOp {
26 Set { key: Vec<u8>, value: Vec<u8> },
27 Del { keys: Vec<Vec<u8>> },
28 Incr { key: Vec<u8> },
29 IncrBy { key: Vec<u8>, delta: i64 },
30 HSet { key: Vec<u8>, pairs: Vec<(Vec<u8>, Vec<u8>)> },
31 HDel { key: Vec<u8>, fields: Vec<Vec<u8>> },
32 HIncrBy { key: Vec<u8>, field: Vec<u8>, delta: i64 },
33 ZAdd { key: Vec<u8>, pairs: Vec<(f64, Vec<u8>)> },
34 ZAddFlags { key: Vec<u8>, pairs: Vec<(f64, Vec<u8>)>, flags: kevy_store::ZaddFlags },
35 ZRem { key: Vec<u8>, members: Vec<Vec<u8>> },
36 ZIncrBy { key: Vec<u8>, delta: f64, member: Vec<u8> },
37 SAdd { key: Vec<u8>, members: Vec<Vec<u8>> },
38 SRem { key: Vec<u8>, members: Vec<Vec<u8>> },
39 LPush { key: Vec<u8>, values: Vec<Vec<u8>> },
40 RPush { key: Vec<u8>, values: Vec<Vec<u8>> },
41}
42
43impl<'a> Pipeline<'a> {
44 pub(crate) fn new(store: &'a Store) -> Self {
45 Self { store, ops: Vec::new() }
46 }
47
48 pub fn len(&self) -> usize {
50 self.ops.len()
51 }
52
53 pub fn is_empty(&self) -> bool {
55 self.ops.is_empty()
56 }
57
58 pub fn set(mut self, key: &[u8], value: &[u8]) -> Self {
61 self.ops.push(PendingOp::Set {
62 key: key.to_vec(),
63 value: value.to_vec(),
64 });
65 self
66 }
67
68 pub fn del(mut self, keys: &[&[u8]]) -> Self {
69 self.ops.push(PendingOp::Del {
70 keys: keys.iter().map(|k| k.to_vec()).collect(),
71 });
72 self
73 }
74
75 pub fn incr(mut self, key: &[u8]) -> Self {
76 self.ops.push(PendingOp::Incr { key: key.to_vec() });
77 self
78 }
79
80 pub fn incr_by(mut self, key: &[u8], delta: i64) -> Self {
81 self.ops.push(PendingOp::IncrBy { key: key.to_vec(), delta });
82 self
83 }
84
85 pub fn hset(mut self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Self {
86 self.ops.push(PendingOp::HSet {
87 key: key.to_vec(),
88 pairs: pairs.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect(),
89 });
90 self
91 }
92
93 pub fn hdel(mut self, key: &[u8], fields: &[&[u8]]) -> Self {
94 self.ops.push(PendingOp::HDel {
95 key: key.to_vec(),
96 fields: fields.iter().map(|f| f.to_vec()).collect(),
97 });
98 self
99 }
100
101 pub fn hincrby(mut self, key: &[u8], field: &[u8], delta: i64) -> Self {
102 self.ops.push(PendingOp::HIncrBy {
103 key: key.to_vec(),
104 field: field.to_vec(),
105 delta,
106 });
107 self
108 }
109
110 pub fn zadd(mut self, key: &[u8], pairs: &[(f64, &[u8])]) -> Self {
111 self.ops.push(PendingOp::ZAdd {
112 key: key.to_vec(),
113 pairs: pairs.iter().map(|(s, m)| (*s, m.to_vec())).collect(),
114 });
115 self
116 }
117
118 pub fn zadd_flags(
120 mut self,
121 key: &[u8],
122 pairs: &[(f64, &[u8])],
123 flags: kevy_store::ZaddFlags,
124 ) -> Self {
125 self.ops.push(PendingOp::ZAddFlags {
126 key: key.to_vec(),
127 pairs: pairs.iter().map(|(s, m)| (*s, m.to_vec())).collect(),
128 flags,
129 });
130 self
131 }
132
133 pub fn zrem(mut self, key: &[u8], members: &[&[u8]]) -> Self {
134 self.ops.push(PendingOp::ZRem {
135 key: key.to_vec(),
136 members: members.iter().map(|m| m.to_vec()).collect(),
137 });
138 self
139 }
140
141 pub fn zincrby(mut self, key: &[u8], delta: f64, member: &[u8]) -> Self {
142 self.ops.push(PendingOp::ZIncrBy {
143 key: key.to_vec(),
144 delta,
145 member: member.to_vec(),
146 });
147 self
148 }
149
150 pub fn sadd(mut self, key: &[u8], members: &[&[u8]]) -> Self {
151 self.ops.push(PendingOp::SAdd {
152 key: key.to_vec(),
153 members: members.iter().map(|m| m.to_vec()).collect(),
154 });
155 self
156 }
157
158 pub fn srem(mut self, key: &[u8], members: &[&[u8]]) -> Self {
159 self.ops.push(PendingOp::SRem {
160 key: key.to_vec(),
161 members: members.iter().map(|m| m.to_vec()).collect(),
162 });
163 self
164 }
165
166 pub fn lpush(mut self, key: &[u8], values: &[&[u8]]) -> Self {
167 self.ops.push(PendingOp::LPush {
168 key: key.to_vec(),
169 values: values.iter().map(|v| v.to_vec()).collect(),
170 });
171 self
172 }
173
174 pub fn rpush(mut self, key: &[u8], values: &[&[u8]]) -> Self {
175 self.ops.push(PendingOp::RPush {
176 key: key.to_vec(),
177 values: values.iter().map(|v| v.to_vec()).collect(),
178 });
179 self
180 }
181
182 pub fn commit(mut self) -> io::Result<()> {
187 let ops = std::mem::take(&mut self.ops);
188 for op in ops {
189 self.apply_one(op)?;
190 }
191 Ok(())
192 }
193
194 fn apply_one(&self, op: PendingOp) -> io::Result<()> {
195 match op {
196 PendingOp::Set { key, value } => {
197 self.store.set(&key, &value)?;
198 }
199 PendingOp::Del { keys } => {
200 let refs: Vec<&[u8]> = keys.iter().map(|k| k.as_slice()).collect();
201 self.store.del(&refs)?;
202 }
203 PendingOp::Incr { key } => {
204 self.store.incr(&key)?;
205 }
206 PendingOp::IncrBy { key, delta } => {
207 self.store.incr_by(&key, delta)?;
208 }
209 PendingOp::HSet { key, pairs } => {
210 let refs: Vec<(&[u8], &[u8])> =
211 pairs.iter().map(|(f, v)| (f.as_slice(), v.as_slice())).collect();
212 self.store.hset(&key, &refs)?;
213 }
214 PendingOp::HDel { key, fields } => {
215 let refs: Vec<&[u8]> = fields.iter().map(|f| f.as_slice()).collect();
216 self.store.hdel(&key, &refs)?;
217 }
218 PendingOp::HIncrBy { key, field, delta } => {
219 self.store.hincrby(&key, &field, delta)?;
220 }
221 PendingOp::ZAdd { key, pairs } => {
222 let refs: Vec<(f64, &[u8])> =
223 pairs.iter().map(|(s, m)| (*s, m.as_slice())).collect();
224 self.store.zadd(&key, &refs)?;
225 }
226 PendingOp::ZAddFlags { key, pairs, flags } => {
227 let refs: Vec<(f64, &[u8])> =
228 pairs.iter().map(|(s, m)| (*s, m.as_slice())).collect();
229 self.store.zadd_flags(&key, &refs, flags)?;
230 }
231 PendingOp::ZRem { key, members } => {
232 let refs: Vec<&[u8]> = members.iter().map(|m| m.as_slice()).collect();
233 self.store.zrem(&key, &refs)?;
234 }
235 PendingOp::ZIncrBy { key, delta, member } => {
236 self.store.zincrby(&key, delta, &member)?;
237 }
238 PendingOp::SAdd { key, members } => {
239 let refs: Vec<&[u8]> = members.iter().map(|m| m.as_slice()).collect();
240 self.store.sadd(&key, &refs)?;
241 }
242 PendingOp::SRem { key, members } => {
243 let refs: Vec<&[u8]> = members.iter().map(|m| m.as_slice()).collect();
244 self.store.srem(&key, &refs)?;
245 }
246 PendingOp::LPush { key, values } => {
247 let refs: Vec<&[u8]> = values.iter().map(|v| v.as_slice()).collect();
248 self.store.lpush(&key, &refs)?;
249 }
250 PendingOp::RPush { key, values } => {
251 let refs: Vec<&[u8]> = values.iter().map(|v| v.as_slice()).collect();
252 self.store.rpush(&key, &refs)?;
253 }
254 }
255 Ok(())
256 }
257}
258
259impl Store {
260 pub fn pipeline(&self) -> Pipeline<'_> {
263 Pipeline::new(self)
264 }
265}
266
267#[cfg_attr(not(test), allow(dead_code))]
271pub(crate) const PIPELINE_OPS: &[&str] = &[
272 "SET", "DEL", "INCR", "INCRBY", "HSET", "HDEL", "HINCRBY", "ZADD",
273 "ZREM", "ZINCRBY", "SADD", "SREM", "LPUSH", "RPUSH",
274];