1 /**************************************************************************
2    Copyright (c) 2017 sewenew
3 
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7 
8        http://www.apache.org/licenses/LICENSE-2.0
9 
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15  *************************************************************************/
16 
17 #include "command.h"
18 #include <cassert>
19 
20 namespace sw {
21 
22 namespace redis {
23 
24 namespace cmd {
25 
26 // KEY commands.
27 
restore(Connection & connection,const StringView & key,const StringView & val,long long ttl,bool replace)28 void restore(Connection &connection,
29                 const StringView &key,
30                 const StringView &val,
31                 long long ttl,
32                 bool replace) {
33     CmdArgs args;
34     args << "RESTORE" << key << ttl << val;
35 
36     if (replace) {
37         args << "REPLACE";
38     }
39 
40     connection.send(args);
41 }
42 
43 // STRING commands.
44 
bitop(Connection & connection,BitOp op,const StringView & destination,const StringView & key)45 void bitop(Connection &connection,
46             BitOp op,
47             const StringView &destination,
48             const StringView &key) {
49     CmdArgs args;
50 
51     detail::set_bitop(args, op);
52 
53     args << destination << key;
54 
55     connection.send(args);
56 }
57 
set(Connection & connection,const StringView & key,const StringView & val,long long ttl,UpdateType type)58 void set(Connection &connection,
59             const StringView &key,
60             const StringView &val,
61             long long ttl,
62             UpdateType type) {
63     CmdArgs args;
64     args << "SET" << key << val;
65 
66     if (ttl > 0) {
67         args << "PX" << ttl;
68     }
69 
70     detail::set_update_type(args, type);
71 
72     connection.send(args);
73 }
74 
75 // LIST commands.
76 
linsert(Connection & connection,const StringView & key,InsertPosition position,const StringView & pivot,const StringView & val)77 void linsert(Connection &connection,
78                 const StringView &key,
79                 InsertPosition position,
80                 const StringView &pivot,
81                 const StringView &val) {
82     std::string pos;
83     switch (position) {
84     case InsertPosition::BEFORE:
85         pos = "BEFORE";
86         break;
87 
88     case InsertPosition::AFTER:
89         pos = "AFTER";
90         break;
91 
92     default:
93         assert(false);
94     }
95 
96     connection.send("LINSERT %b %s %b %b",
97                     key.data(), key.size(),
98                     pos.c_str(),
99                     pivot.data(), pivot.size(),
100                     val.data(), val.size());
101 }
102 
103 // GEO commands.
104 
geodist(Connection & connection,const StringView & key,const StringView & member1,const StringView & member2,GeoUnit unit)105 void geodist(Connection &connection,
106                 const StringView &key,
107                 const StringView &member1,
108                 const StringView &member2,
109                 GeoUnit unit) {
110     CmdArgs args;
111     args << "GEODIST" << key << member1 << member2;
112 
113     detail::set_geo_unit(args, unit);
114 
115     connection.send(args);
116 }
117 
georadius_store(Connection & connection,const StringView & key,const std::pair<double,double> & loc,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)118 void georadius_store(Connection &connection,
119                         const StringView &key,
120                         const std::pair<double, double> &loc,
121                         double radius,
122                         GeoUnit unit,
123                         const StringView &destination,
124                         bool store_dist,
125                         long long count) {
126     CmdArgs args;
127     args << "GEORADIUS" << key << loc.first << loc.second;
128 
129     detail::set_georadius_store_parameters(args,
130                                             radius,
131                                             unit,
132                                             destination,
133                                             store_dist,
134                                             count);
135 
136     connection.send(args);
137 }
138 
georadius(Connection & connection,const StringView & key,const std::pair<double,double> & loc,double radius,GeoUnit unit,long long count,bool asc,bool with_coord,bool with_dist,bool with_hash)139 void georadius(Connection &connection,
140                 const StringView &key,
141                 const std::pair<double, double> &loc,
142                 double radius,
143                 GeoUnit unit,
144                 long long count,
145                 bool asc,
146                 bool with_coord,
147                 bool with_dist,
148                 bool with_hash) {
149     CmdArgs args;
150     args << "GEORADIUS" << key << loc.first << loc.second;
151 
152     detail::set_georadius_parameters(args,
153                                         radius,
154                                         unit,
155                                         count,
156                                         asc,
157                                         with_coord,
158                                         with_dist,
159                                         with_hash);
160 
161     connection.send(args);
162 }
163 
georadiusbymember(Connection & connection,const StringView & key,const StringView & member,double radius,GeoUnit unit,long long count,bool asc,bool with_coord,bool with_dist,bool with_hash)164 void georadiusbymember(Connection &connection,
165                         const StringView &key,
166                         const StringView &member,
167                         double radius,
168                         GeoUnit unit,
169                         long long count,
170                         bool asc,
171                         bool with_coord,
172                         bool with_dist,
173                         bool with_hash) {
174     CmdArgs args;
175     args << "GEORADIUSBYMEMBER" << key << member;
176 
177     detail::set_georadius_parameters(args,
178                                         radius,
179                                         unit,
180                                         count,
181                                         asc,
182                                         with_coord,
183                                         with_dist,
184                                         with_hash);
185 
186     connection.send(args);
187 }
188 
georadiusbymember_store(Connection & connection,const StringView & key,const StringView & member,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)189 void georadiusbymember_store(Connection &connection,
190                                 const StringView &key,
191                                 const StringView &member,
192                                 double radius,
193                                 GeoUnit unit,
194                                 const StringView &destination,
195                                 bool store_dist,
196                                 long long count) {
197     CmdArgs args;
198     args << "GEORADIUSBYMEMBER" << key << member;
199 
200     detail::set_georadius_store_parameters(args,
201                                             radius,
202                                             unit,
203                                             destination,
204                                             store_dist,
205                                             count);
206 
207     connection.send(args);
208 }
209 
210 // Stream commands.
211 
xtrim(Connection & connection,const StringView & key,long long count,bool approx)212 void xtrim(Connection &connection, const StringView &key, long long count, bool approx) {
213     CmdArgs args;
214     args << "XTRIM" << key << "MAXLEN";
215 
216     if (approx) {
217         args << "~";
218     }
219 
220     args << count;
221 
222     connection.send(args);
223 }
224 
225 namespace detail {
226 
set_bitop(CmdArgs & args,BitOp op)227 void set_bitop(CmdArgs &args, BitOp op) {
228     args << "BITOP";
229 
230     switch (op) {
231     case BitOp::AND:
232         args << "AND";
233         break;
234 
235     case BitOp::OR:
236         args << "OR";
237         break;
238 
239     case BitOp::XOR:
240         args << "XOR";
241         break;
242 
243     case BitOp::NOT:
244         args << "NOT";
245         break;
246 
247     default:
248         throw Error("Unknown bit operations");
249     }
250 }
251 
set_update_type(CmdArgs & args,UpdateType type)252 void set_update_type(CmdArgs &args, UpdateType type) {
253     switch (type) {
254     case UpdateType::EXIST:
255         args << "XX";
256         break;
257 
258     case UpdateType::NOT_EXIST:
259         args << "NX";
260         break;
261 
262     case UpdateType::ALWAYS:
263         // Do nothing.
264         break;
265 
266     default:
267         throw Error("Unknown update type");
268     }
269 }
270 
set_aggregation_type(CmdArgs & args,Aggregation aggr)271 void set_aggregation_type(CmdArgs &args, Aggregation aggr) {
272     args << "AGGREGATE";
273 
274     switch (aggr) {
275     case Aggregation::SUM:
276         args << "SUM";
277         break;
278 
279     case Aggregation::MIN:
280         args << "MIN";
281         break;
282 
283     case Aggregation::MAX:
284         args << "MAX";
285         break;
286 
287     default:
288         throw Error("Unknown aggregation type");
289     }
290 }
291 
set_geo_unit(CmdArgs & args,GeoUnit unit)292 void set_geo_unit(CmdArgs &args, GeoUnit unit) {
293     switch (unit) {
294     case GeoUnit::M:
295         args << "m";
296         break;
297 
298     case GeoUnit::KM:
299         args << "km";
300         break;
301 
302     case GeoUnit::MI:
303         args << "mi";
304         break;
305 
306     case GeoUnit::FT:
307         args << "ft";
308         break;
309 
310     default:
311         throw Error("Unknown geo unit type");
312         break;
313     }
314 }
315 
set_georadius_store_parameters(CmdArgs & args,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)316 void set_georadius_store_parameters(CmdArgs &args,
317                                     double radius,
318                                     GeoUnit unit,
319                                     const StringView &destination,
320                                     bool store_dist,
321                                     long long count) {
322     args << radius;
323 
324     detail::set_geo_unit(args, unit);
325 
326     args << "COUNT" << count;
327 
328     if (store_dist) {
329         args << "STOREDIST";
330     } else {
331         args << "STORE";
332     }
333 
334     args << destination;
335 }
336 
set_georadius_parameters(CmdArgs & args,double radius,GeoUnit unit,long long count,bool asc,bool with_coord,bool with_dist,bool with_hash)337 void set_georadius_parameters(CmdArgs &args,
338                                 double radius,
339                                 GeoUnit unit,
340                                 long long count,
341                                 bool asc,
342                                 bool with_coord,
343                                 bool with_dist,
344                                 bool with_hash) {
345     args << radius;
346 
347     detail::set_geo_unit(args, unit);
348 
349     if (with_coord) {
350         args << "WITHCOORD";
351     }
352 
353     if (with_dist) {
354         args << "WITHDIST";
355     }
356 
357     if (with_hash) {
358         args << "WITHHASH";
359     }
360 
361     args << "COUNT" << count;
362 
363     if (asc) {
364         args << "ASC";
365     } else {
366         args << "DESC";
367     }
368 }
369 
370 }
371 
372 }
373 
374 }
375 
376 }
377