1*572c4311Sfengbojiang /* Helloworld module -- A few examples of the Redis Modules API in the form
2*572c4311Sfengbojiang  * of commands showing how to accomplish common tasks.
3*572c4311Sfengbojiang  *
4*572c4311Sfengbojiang  * This module does not do anything useful, if not for a few commands. The
5*572c4311Sfengbojiang  * examples are designed in order to show the API.
6*572c4311Sfengbojiang  *
7*572c4311Sfengbojiang  * -----------------------------------------------------------------------------
8*572c4311Sfengbojiang  *
9*572c4311Sfengbojiang  * Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
10*572c4311Sfengbojiang  * All rights reserved.
11*572c4311Sfengbojiang  *
12*572c4311Sfengbojiang  * Redistribution and use in source and binary forms, with or without
13*572c4311Sfengbojiang  * modification, are permitted provided that the following conditions are met:
14*572c4311Sfengbojiang  *
15*572c4311Sfengbojiang  *   * Redistributions of source code must retain the above copyright notice,
16*572c4311Sfengbojiang  *     this list of conditions and the following disclaimer.
17*572c4311Sfengbojiang  *   * Redistributions in binary form must reproduce the above copyright
18*572c4311Sfengbojiang  *     notice, this list of conditions and the following disclaimer in the
19*572c4311Sfengbojiang  *     documentation and/or other materials provided with the distribution.
20*572c4311Sfengbojiang  *   * Neither the name of Redis nor the names of its contributors may be used
21*572c4311Sfengbojiang  *     to endorse or promote products derived from this software without
22*572c4311Sfengbojiang  *     specific prior written permission.
23*572c4311Sfengbojiang  *
24*572c4311Sfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25*572c4311Sfengbojiang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*572c4311Sfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*572c4311Sfengbojiang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28*572c4311Sfengbojiang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29*572c4311Sfengbojiang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30*572c4311Sfengbojiang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31*572c4311Sfengbojiang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32*572c4311Sfengbojiang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33*572c4311Sfengbojiang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34*572c4311Sfengbojiang  * POSSIBILITY OF SUCH DAMAGE.
35*572c4311Sfengbojiang  */
36*572c4311Sfengbojiang 
37*572c4311Sfengbojiang #include "../redismodule.h"
38*572c4311Sfengbojiang #include <stdio.h>
39*572c4311Sfengbojiang #include <stdlib.h>
40*572c4311Sfengbojiang #include <ctype.h>
41*572c4311Sfengbojiang #include <string.h>
42*572c4311Sfengbojiang 
43*572c4311Sfengbojiang /* HELLO.SIMPLE is among the simplest commands you can implement.
44*572c4311Sfengbojiang  * It just returns the currently selected DB id, a functionality which is
45*572c4311Sfengbojiang  * missing in Redis. The command uses two important API calls: one to
46*572c4311Sfengbojiang  * fetch the currently selected DB, the other in order to send the client
47*572c4311Sfengbojiang  * an integer reply as response. */
HelloSimple_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)48*572c4311Sfengbojiang int HelloSimple_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
49*572c4311Sfengbojiang     REDISMODULE_NOT_USED(argv);
50*572c4311Sfengbojiang     REDISMODULE_NOT_USED(argc);
51*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,RedisModule_GetSelectedDb(ctx));
52*572c4311Sfengbojiang     return REDISMODULE_OK;
53*572c4311Sfengbojiang }
54*572c4311Sfengbojiang 
55*572c4311Sfengbojiang /* HELLO.PUSH.NATIVE re-implements RPUSH, and shows the low level modules API
56*572c4311Sfengbojiang  * where you can "open" keys, make low level operations, create new keys by
57*572c4311Sfengbojiang  * pushing elements into non-existing keys, and so forth.
58*572c4311Sfengbojiang  *
59*572c4311Sfengbojiang  * You'll find this command to be roughly as fast as the actual RPUSH
60*572c4311Sfengbojiang  * command. */
HelloPushNative_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)61*572c4311Sfengbojiang int HelloPushNative_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
62*572c4311Sfengbojiang {
63*572c4311Sfengbojiang     if (argc != 3) return RedisModule_WrongArity(ctx);
64*572c4311Sfengbojiang 
65*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
66*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
67*572c4311Sfengbojiang 
68*572c4311Sfengbojiang     RedisModule_ListPush(key,REDISMODULE_LIST_TAIL,argv[2]);
69*572c4311Sfengbojiang     size_t newlen = RedisModule_ValueLength(key);
70*572c4311Sfengbojiang     RedisModule_CloseKey(key);
71*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,newlen);
72*572c4311Sfengbojiang     return REDISMODULE_OK;
73*572c4311Sfengbojiang }
74*572c4311Sfengbojiang 
75*572c4311Sfengbojiang /* HELLO.PUSH.CALL implements RPUSH using an higher level approach, calling
76*572c4311Sfengbojiang  * a Redis command instead of working with the key in a low level way. This
77*572c4311Sfengbojiang  * approach is useful when you need to call Redis commands that are not
78*572c4311Sfengbojiang  * available as low level APIs, or when you don't need the maximum speed
79*572c4311Sfengbojiang  * possible but instead prefer implementation simplicity. */
HelloPushCall_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)80*572c4311Sfengbojiang int HelloPushCall_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
81*572c4311Sfengbojiang {
82*572c4311Sfengbojiang     if (argc != 3) return RedisModule_WrongArity(ctx);
83*572c4311Sfengbojiang 
84*572c4311Sfengbojiang     RedisModuleCallReply *reply;
85*572c4311Sfengbojiang 
86*572c4311Sfengbojiang     reply = RedisModule_Call(ctx,"RPUSH","ss",argv[1],argv[2]);
87*572c4311Sfengbojiang     long long len = RedisModule_CallReplyInteger(reply);
88*572c4311Sfengbojiang     RedisModule_FreeCallReply(reply);
89*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,len);
90*572c4311Sfengbojiang     return REDISMODULE_OK;
91*572c4311Sfengbojiang }
92*572c4311Sfengbojiang 
93*572c4311Sfengbojiang /* HELLO.PUSH.CALL2
94*572c4311Sfengbojiang  * This is exaxctly as HELLO.PUSH.CALL, but shows how we can reply to the
95*572c4311Sfengbojiang  * client using directly a reply object that Call() returned. */
HelloPushCall2_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)96*572c4311Sfengbojiang int HelloPushCall2_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
97*572c4311Sfengbojiang {
98*572c4311Sfengbojiang     if (argc != 3) return RedisModule_WrongArity(ctx);
99*572c4311Sfengbojiang 
100*572c4311Sfengbojiang     RedisModuleCallReply *reply;
101*572c4311Sfengbojiang 
102*572c4311Sfengbojiang     reply = RedisModule_Call(ctx,"RPUSH","ss",argv[1],argv[2]);
103*572c4311Sfengbojiang     RedisModule_ReplyWithCallReply(ctx,reply);
104*572c4311Sfengbojiang     RedisModule_FreeCallReply(reply);
105*572c4311Sfengbojiang     return REDISMODULE_OK;
106*572c4311Sfengbojiang }
107*572c4311Sfengbojiang 
108*572c4311Sfengbojiang /* HELLO.LIST.SUM.LEN returns the total length of all the items inside
109*572c4311Sfengbojiang  * a Redis list, by using the high level Call() API.
110*572c4311Sfengbojiang  * This command is an example of the array reply access. */
HelloListSumLen_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)111*572c4311Sfengbojiang int HelloListSumLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
112*572c4311Sfengbojiang {
113*572c4311Sfengbojiang     if (argc != 2) return RedisModule_WrongArity(ctx);
114*572c4311Sfengbojiang 
115*572c4311Sfengbojiang     RedisModuleCallReply *reply;
116*572c4311Sfengbojiang 
117*572c4311Sfengbojiang     reply = RedisModule_Call(ctx,"LRANGE","sll",argv[1],(long long)0,(long long)-1);
118*572c4311Sfengbojiang     size_t strlen = 0;
119*572c4311Sfengbojiang     size_t items = RedisModule_CallReplyLength(reply);
120*572c4311Sfengbojiang     size_t j;
121*572c4311Sfengbojiang     for (j = 0; j < items; j++) {
122*572c4311Sfengbojiang         RedisModuleCallReply *ele = RedisModule_CallReplyArrayElement(reply,j);
123*572c4311Sfengbojiang         strlen += RedisModule_CallReplyLength(ele);
124*572c4311Sfengbojiang     }
125*572c4311Sfengbojiang     RedisModule_FreeCallReply(reply);
126*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,strlen);
127*572c4311Sfengbojiang     return REDISMODULE_OK;
128*572c4311Sfengbojiang }
129*572c4311Sfengbojiang 
130*572c4311Sfengbojiang /* HELLO.LIST.SPLICE srclist dstlist count
131*572c4311Sfengbojiang  * Moves 'count' elements from the tail of 'srclist' to the head of
132*572c4311Sfengbojiang  * 'dstlist'. If less than count elements are available, it moves as much
133*572c4311Sfengbojiang  * elements as possible. */
HelloListSplice_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)134*572c4311Sfengbojiang int HelloListSplice_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
135*572c4311Sfengbojiang     if (argc != 4) return RedisModule_WrongArity(ctx);
136*572c4311Sfengbojiang 
137*572c4311Sfengbojiang     RedisModuleKey *srckey = RedisModule_OpenKey(ctx,argv[1],
138*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
139*572c4311Sfengbojiang     RedisModuleKey *dstkey = RedisModule_OpenKey(ctx,argv[2],
140*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
141*572c4311Sfengbojiang 
142*572c4311Sfengbojiang     /* Src and dst key must be empty or lists. */
143*572c4311Sfengbojiang     if ((RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_LIST &&
144*572c4311Sfengbojiang          RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_EMPTY) ||
145*572c4311Sfengbojiang         (RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_LIST &&
146*572c4311Sfengbojiang          RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_EMPTY))
147*572c4311Sfengbojiang     {
148*572c4311Sfengbojiang         RedisModule_CloseKey(srckey);
149*572c4311Sfengbojiang         RedisModule_CloseKey(dstkey);
150*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
151*572c4311Sfengbojiang     }
152*572c4311Sfengbojiang 
153*572c4311Sfengbojiang     long long count;
154*572c4311Sfengbojiang     if ((RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK) ||
155*572c4311Sfengbojiang         (count < 0)) {
156*572c4311Sfengbojiang         RedisModule_CloseKey(srckey);
157*572c4311Sfengbojiang         RedisModule_CloseKey(dstkey);
158*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid count");
159*572c4311Sfengbojiang     }
160*572c4311Sfengbojiang 
161*572c4311Sfengbojiang     while(count-- > 0) {
162*572c4311Sfengbojiang         RedisModuleString *ele;
163*572c4311Sfengbojiang 
164*572c4311Sfengbojiang         ele = RedisModule_ListPop(srckey,REDISMODULE_LIST_TAIL);
165*572c4311Sfengbojiang         if (ele == NULL) break;
166*572c4311Sfengbojiang         RedisModule_ListPush(dstkey,REDISMODULE_LIST_HEAD,ele);
167*572c4311Sfengbojiang         RedisModule_FreeString(ctx,ele);
168*572c4311Sfengbojiang     }
169*572c4311Sfengbojiang 
170*572c4311Sfengbojiang     size_t len = RedisModule_ValueLength(srckey);
171*572c4311Sfengbojiang     RedisModule_CloseKey(srckey);
172*572c4311Sfengbojiang     RedisModule_CloseKey(dstkey);
173*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,len);
174*572c4311Sfengbojiang     return REDISMODULE_OK;
175*572c4311Sfengbojiang }
176*572c4311Sfengbojiang 
177*572c4311Sfengbojiang /* Like the HELLO.LIST.SPLICE above, but uses automatic memory management
178*572c4311Sfengbojiang  * in order to avoid freeing stuff. */
HelloListSpliceAuto_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)179*572c4311Sfengbojiang int HelloListSpliceAuto_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
180*572c4311Sfengbojiang     if (argc != 4) return RedisModule_WrongArity(ctx);
181*572c4311Sfengbojiang 
182*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx);
183*572c4311Sfengbojiang 
184*572c4311Sfengbojiang     RedisModuleKey *srckey = RedisModule_OpenKey(ctx,argv[1],
185*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
186*572c4311Sfengbojiang     RedisModuleKey *dstkey = RedisModule_OpenKey(ctx,argv[2],
187*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
188*572c4311Sfengbojiang 
189*572c4311Sfengbojiang     /* Src and dst key must be empty or lists. */
190*572c4311Sfengbojiang     if ((RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_LIST &&
191*572c4311Sfengbojiang          RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_EMPTY) ||
192*572c4311Sfengbojiang         (RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_LIST &&
193*572c4311Sfengbojiang          RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_EMPTY))
194*572c4311Sfengbojiang     {
195*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
196*572c4311Sfengbojiang     }
197*572c4311Sfengbojiang 
198*572c4311Sfengbojiang     long long count;
199*572c4311Sfengbojiang     if ((RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK) ||
200*572c4311Sfengbojiang         (count < 0))
201*572c4311Sfengbojiang     {
202*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid count");
203*572c4311Sfengbojiang     }
204*572c4311Sfengbojiang 
205*572c4311Sfengbojiang     while(count-- > 0) {
206*572c4311Sfengbojiang         RedisModuleString *ele;
207*572c4311Sfengbojiang 
208*572c4311Sfengbojiang         ele = RedisModule_ListPop(srckey,REDISMODULE_LIST_TAIL);
209*572c4311Sfengbojiang         if (ele == NULL) break;
210*572c4311Sfengbojiang         RedisModule_ListPush(dstkey,REDISMODULE_LIST_HEAD,ele);
211*572c4311Sfengbojiang     }
212*572c4311Sfengbojiang 
213*572c4311Sfengbojiang     size_t len = RedisModule_ValueLength(srckey);
214*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,len);
215*572c4311Sfengbojiang     return REDISMODULE_OK;
216*572c4311Sfengbojiang }
217*572c4311Sfengbojiang 
218*572c4311Sfengbojiang /* HELLO.RAND.ARRAY <count>
219*572c4311Sfengbojiang  * Shows how to generate arrays as commands replies.
220*572c4311Sfengbojiang  * It just outputs <count> random numbers. */
HelloRandArray_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)221*572c4311Sfengbojiang int HelloRandArray_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
222*572c4311Sfengbojiang     if (argc != 2) return RedisModule_WrongArity(ctx);
223*572c4311Sfengbojiang     long long count;
224*572c4311Sfengbojiang     if (RedisModule_StringToLongLong(argv[1],&count) != REDISMODULE_OK ||
225*572c4311Sfengbojiang         count < 0)
226*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid count");
227*572c4311Sfengbojiang 
228*572c4311Sfengbojiang     /* To reply with an array, we call RedisModule_ReplyWithArray() followed
229*572c4311Sfengbojiang      * by other "count" calls to other reply functions in order to generate
230*572c4311Sfengbojiang      * the elements of the array. */
231*572c4311Sfengbojiang     RedisModule_ReplyWithArray(ctx,count);
232*572c4311Sfengbojiang     while(count--) RedisModule_ReplyWithLongLong(ctx,rand());
233*572c4311Sfengbojiang     return REDISMODULE_OK;
234*572c4311Sfengbojiang }
235*572c4311Sfengbojiang 
236*572c4311Sfengbojiang /* This is a simple command to test replication. Because of the "!" modified
237*572c4311Sfengbojiang  * in the RedisModule_Call() call, the two INCRs get replicated.
238*572c4311Sfengbojiang  * Also note how the ECHO is replicated in an unexpected position (check
239*572c4311Sfengbojiang  * comments the function implementation). */
HelloRepl1_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)240*572c4311Sfengbojiang int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
241*572c4311Sfengbojiang {
242*572c4311Sfengbojiang     REDISMODULE_NOT_USED(argv);
243*572c4311Sfengbojiang     REDISMODULE_NOT_USED(argc);
244*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx);
245*572c4311Sfengbojiang 
246*572c4311Sfengbojiang     /* This will be replicated *after* the two INCR statements, since
247*572c4311Sfengbojiang      * the Call() replication has precedence, so the actual replication
248*572c4311Sfengbojiang      * stream will be:
249*572c4311Sfengbojiang      *
250*572c4311Sfengbojiang      * MULTI
251*572c4311Sfengbojiang      * INCR foo
252*572c4311Sfengbojiang      * INCR bar
253*572c4311Sfengbojiang      * ECHO c foo
254*572c4311Sfengbojiang      * EXEC
255*572c4311Sfengbojiang      */
256*572c4311Sfengbojiang     RedisModule_Replicate(ctx,"ECHO","c","foo");
257*572c4311Sfengbojiang 
258*572c4311Sfengbojiang     /* Using the "!" modifier we replicate the command if it
259*572c4311Sfengbojiang      * modified the dataset in some way. */
260*572c4311Sfengbojiang     RedisModule_Call(ctx,"INCR","c!","foo");
261*572c4311Sfengbojiang     RedisModule_Call(ctx,"INCR","c!","bar");
262*572c4311Sfengbojiang 
263*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,0);
264*572c4311Sfengbojiang 
265*572c4311Sfengbojiang     return REDISMODULE_OK;
266*572c4311Sfengbojiang }
267*572c4311Sfengbojiang 
268*572c4311Sfengbojiang /* Another command to show replication. In this case, we call
269*572c4311Sfengbojiang  * RedisModule_ReplicateVerbatim() to mean we want just the command to be
270*572c4311Sfengbojiang  * propagated to slaves / AOF exactly as it was called by the user.
271*572c4311Sfengbojiang  *
272*572c4311Sfengbojiang  * This command also shows how to work with string objects.
273*572c4311Sfengbojiang  * It takes a list, and increments all the elements (that must have
274*572c4311Sfengbojiang  * a numerical value) by 1, returning the sum of all the elements
275*572c4311Sfengbojiang  * as reply.
276*572c4311Sfengbojiang  *
277*572c4311Sfengbojiang  * Usage: HELLO.REPL2 <list-key> */
HelloRepl2_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)278*572c4311Sfengbojiang int HelloRepl2_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
279*572c4311Sfengbojiang     if (argc != 2) return RedisModule_WrongArity(ctx);
280*572c4311Sfengbojiang 
281*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
282*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
283*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
284*572c4311Sfengbojiang 
285*572c4311Sfengbojiang     if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_LIST)
286*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
287*572c4311Sfengbojiang 
288*572c4311Sfengbojiang     size_t listlen = RedisModule_ValueLength(key);
289*572c4311Sfengbojiang     long long sum = 0;
290*572c4311Sfengbojiang 
291*572c4311Sfengbojiang     /* Rotate and increment. */
292*572c4311Sfengbojiang     while(listlen--) {
293*572c4311Sfengbojiang         RedisModuleString *ele = RedisModule_ListPop(key,REDISMODULE_LIST_TAIL);
294*572c4311Sfengbojiang         long long val;
295*572c4311Sfengbojiang         if (RedisModule_StringToLongLong(ele,&val) != REDISMODULE_OK) val = 0;
296*572c4311Sfengbojiang         val++;
297*572c4311Sfengbojiang         sum += val;
298*572c4311Sfengbojiang         RedisModuleString *newele = RedisModule_CreateStringFromLongLong(ctx,val);
299*572c4311Sfengbojiang         RedisModule_ListPush(key,REDISMODULE_LIST_HEAD,newele);
300*572c4311Sfengbojiang     }
301*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,sum);
302*572c4311Sfengbojiang     RedisModule_ReplicateVerbatim(ctx);
303*572c4311Sfengbojiang     return REDISMODULE_OK;
304*572c4311Sfengbojiang }
305*572c4311Sfengbojiang 
306*572c4311Sfengbojiang /* This is an example of strings DMA access. Given a key containing a string
307*572c4311Sfengbojiang  * it toggles the case of each character from lower to upper case or the
308*572c4311Sfengbojiang  * other way around.
309*572c4311Sfengbojiang  *
310*572c4311Sfengbojiang  * No automatic memory management is used in this example (for the sake
311*572c4311Sfengbojiang  * of variety).
312*572c4311Sfengbojiang  *
313*572c4311Sfengbojiang  * HELLO.TOGGLE.CASE key */
HelloToggleCase_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)314*572c4311Sfengbojiang int HelloToggleCase_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
315*572c4311Sfengbojiang     if (argc != 2) return RedisModule_WrongArity(ctx);
316*572c4311Sfengbojiang 
317*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
318*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
319*572c4311Sfengbojiang 
320*572c4311Sfengbojiang     int keytype = RedisModule_KeyType(key);
321*572c4311Sfengbojiang     if (keytype != REDISMODULE_KEYTYPE_STRING &&
322*572c4311Sfengbojiang         keytype != REDISMODULE_KEYTYPE_EMPTY)
323*572c4311Sfengbojiang     {
324*572c4311Sfengbojiang         RedisModule_CloseKey(key);
325*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
326*572c4311Sfengbojiang     }
327*572c4311Sfengbojiang 
328*572c4311Sfengbojiang     if (keytype == REDISMODULE_KEYTYPE_STRING) {
329*572c4311Sfengbojiang         size_t len, j;
330*572c4311Sfengbojiang         char *s = RedisModule_StringDMA(key,&len,REDISMODULE_WRITE);
331*572c4311Sfengbojiang         for (j = 0; j < len; j++) {
332*572c4311Sfengbojiang             if (isupper(s[j])) {
333*572c4311Sfengbojiang                 s[j] = tolower(s[j]);
334*572c4311Sfengbojiang             } else {
335*572c4311Sfengbojiang                 s[j] = toupper(s[j]);
336*572c4311Sfengbojiang             }
337*572c4311Sfengbojiang         }
338*572c4311Sfengbojiang     }
339*572c4311Sfengbojiang 
340*572c4311Sfengbojiang     RedisModule_CloseKey(key);
341*572c4311Sfengbojiang     RedisModule_ReplyWithSimpleString(ctx,"OK");
342*572c4311Sfengbojiang     RedisModule_ReplicateVerbatim(ctx);
343*572c4311Sfengbojiang     return REDISMODULE_OK;
344*572c4311Sfengbojiang }
345*572c4311Sfengbojiang 
346*572c4311Sfengbojiang /* HELLO.MORE.EXPIRE key milliseconds.
347*572c4311Sfengbojiang  *
348*572c4311Sfengbojiang  * If they key has already an associated TTL, extends it by "milliseconds"
349*572c4311Sfengbojiang  * milliseconds. Otherwise no operation is performed. */
HelloMoreExpire_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)350*572c4311Sfengbojiang int HelloMoreExpire_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
351*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
352*572c4311Sfengbojiang     if (argc != 3) return RedisModule_WrongArity(ctx);
353*572c4311Sfengbojiang 
354*572c4311Sfengbojiang     mstime_t addms, expire;
355*572c4311Sfengbojiang 
356*572c4311Sfengbojiang     if (RedisModule_StringToLongLong(argv[2],&addms) != REDISMODULE_OK)
357*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid expire time");
358*572c4311Sfengbojiang 
359*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
360*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
361*572c4311Sfengbojiang     expire = RedisModule_GetExpire(key);
362*572c4311Sfengbojiang     if (expire != REDISMODULE_NO_EXPIRE) {
363*572c4311Sfengbojiang         expire += addms;
364*572c4311Sfengbojiang         RedisModule_SetExpire(key,expire);
365*572c4311Sfengbojiang     }
366*572c4311Sfengbojiang     return RedisModule_ReplyWithSimpleString(ctx,"OK");
367*572c4311Sfengbojiang }
368*572c4311Sfengbojiang 
369*572c4311Sfengbojiang /* HELLO.ZSUMRANGE key startscore endscore
370*572c4311Sfengbojiang  * Return the sum of all the scores elements between startscore and endscore.
371*572c4311Sfengbojiang  *
372*572c4311Sfengbojiang  * The computation is performed two times, one time from start to end and
373*572c4311Sfengbojiang  * another time backward. The two scores, returned as a two element array,
374*572c4311Sfengbojiang  * should match.*/
HelloZsumRange_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)375*572c4311Sfengbojiang int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
376*572c4311Sfengbojiang     double score_start, score_end;
377*572c4311Sfengbojiang     if (argc != 4) return RedisModule_WrongArity(ctx);
378*572c4311Sfengbojiang 
379*572c4311Sfengbojiang     if (RedisModule_StringToDouble(argv[2],&score_start) != REDISMODULE_OK ||
380*572c4311Sfengbojiang         RedisModule_StringToDouble(argv[3],&score_end) != REDISMODULE_OK)
381*572c4311Sfengbojiang     {
382*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid range");
383*572c4311Sfengbojiang     }
384*572c4311Sfengbojiang 
385*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
386*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
387*572c4311Sfengbojiang     if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
388*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
389*572c4311Sfengbojiang     }
390*572c4311Sfengbojiang 
391*572c4311Sfengbojiang     double scoresum_a = 0;
392*572c4311Sfengbojiang     double scoresum_b = 0;
393*572c4311Sfengbojiang 
394*572c4311Sfengbojiang     RedisModule_ZsetFirstInScoreRange(key,score_start,score_end,0,0);
395*572c4311Sfengbojiang     while(!RedisModule_ZsetRangeEndReached(key)) {
396*572c4311Sfengbojiang         double score;
397*572c4311Sfengbojiang         RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
398*572c4311Sfengbojiang         RedisModule_FreeString(ctx,ele);
399*572c4311Sfengbojiang         scoresum_a += score;
400*572c4311Sfengbojiang         RedisModule_ZsetRangeNext(key);
401*572c4311Sfengbojiang     }
402*572c4311Sfengbojiang     RedisModule_ZsetRangeStop(key);
403*572c4311Sfengbojiang 
404*572c4311Sfengbojiang     RedisModule_ZsetLastInScoreRange(key,score_start,score_end,0,0);
405*572c4311Sfengbojiang     while(!RedisModule_ZsetRangeEndReached(key)) {
406*572c4311Sfengbojiang         double score;
407*572c4311Sfengbojiang         RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
408*572c4311Sfengbojiang         RedisModule_FreeString(ctx,ele);
409*572c4311Sfengbojiang         scoresum_b += score;
410*572c4311Sfengbojiang         RedisModule_ZsetRangePrev(key);
411*572c4311Sfengbojiang     }
412*572c4311Sfengbojiang 
413*572c4311Sfengbojiang     RedisModule_ZsetRangeStop(key);
414*572c4311Sfengbojiang 
415*572c4311Sfengbojiang     RedisModule_CloseKey(key);
416*572c4311Sfengbojiang 
417*572c4311Sfengbojiang     RedisModule_ReplyWithArray(ctx,2);
418*572c4311Sfengbojiang     RedisModule_ReplyWithDouble(ctx,scoresum_a);
419*572c4311Sfengbojiang     RedisModule_ReplyWithDouble(ctx,scoresum_b);
420*572c4311Sfengbojiang     return REDISMODULE_OK;
421*572c4311Sfengbojiang }
422*572c4311Sfengbojiang 
423*572c4311Sfengbojiang /* HELLO.LEXRANGE key min_lex max_lex min_age max_age
424*572c4311Sfengbojiang  * This command expects a sorted set stored at key in the following form:
425*572c4311Sfengbojiang  * - All the elements have score 0.
426*572c4311Sfengbojiang  * - Elements are pairs of "<name>:<age>", for example "Anna:52".
427*572c4311Sfengbojiang  * The command will return all the sorted set items that are lexicographically
428*572c4311Sfengbojiang  * between the specified range (using the same format as ZRANGEBYLEX)
429*572c4311Sfengbojiang  * and having an age between min_age and max_age. */
HelloLexRange_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)430*572c4311Sfengbojiang int HelloLexRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
431*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
432*572c4311Sfengbojiang 
433*572c4311Sfengbojiang     if (argc != 6) return RedisModule_WrongArity(ctx);
434*572c4311Sfengbojiang 
435*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
436*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
437*572c4311Sfengbojiang     if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
438*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
439*572c4311Sfengbojiang     }
440*572c4311Sfengbojiang 
441*572c4311Sfengbojiang     if (RedisModule_ZsetFirstInLexRange(key,argv[2],argv[3]) != REDISMODULE_OK) {
442*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"invalid range");
443*572c4311Sfengbojiang     }
444*572c4311Sfengbojiang 
445*572c4311Sfengbojiang     int arraylen = 0;
446*572c4311Sfengbojiang     RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_ARRAY_LEN);
447*572c4311Sfengbojiang     while(!RedisModule_ZsetRangeEndReached(key)) {
448*572c4311Sfengbojiang         double score;
449*572c4311Sfengbojiang         RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
450*572c4311Sfengbojiang         RedisModule_ReplyWithString(ctx,ele);
451*572c4311Sfengbojiang         RedisModule_FreeString(ctx,ele);
452*572c4311Sfengbojiang         RedisModule_ZsetRangeNext(key);
453*572c4311Sfengbojiang         arraylen++;
454*572c4311Sfengbojiang     }
455*572c4311Sfengbojiang     RedisModule_ZsetRangeStop(key);
456*572c4311Sfengbojiang     RedisModule_ReplySetArrayLength(ctx,arraylen);
457*572c4311Sfengbojiang     RedisModule_CloseKey(key);
458*572c4311Sfengbojiang     return REDISMODULE_OK;
459*572c4311Sfengbojiang }
460*572c4311Sfengbojiang 
461*572c4311Sfengbojiang /* HELLO.HCOPY key srcfield dstfield
462*572c4311Sfengbojiang  * This is just an example command that sets the hash field dstfield to the
463*572c4311Sfengbojiang  * same value of srcfield. If srcfield does not exist no operation is
464*572c4311Sfengbojiang  * performed.
465*572c4311Sfengbojiang  *
466*572c4311Sfengbojiang  * The command returns 1 if the copy is performed (srcfield exists) otherwise
467*572c4311Sfengbojiang  * 0 is returned. */
HelloHCopy_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)468*572c4311Sfengbojiang int HelloHCopy_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
469*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
470*572c4311Sfengbojiang 
471*572c4311Sfengbojiang     if (argc != 4) return RedisModule_WrongArity(ctx);
472*572c4311Sfengbojiang     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
473*572c4311Sfengbojiang         REDISMODULE_READ|REDISMODULE_WRITE);
474*572c4311Sfengbojiang     int type = RedisModule_KeyType(key);
475*572c4311Sfengbojiang     if (type != REDISMODULE_KEYTYPE_HASH &&
476*572c4311Sfengbojiang         type != REDISMODULE_KEYTYPE_EMPTY)
477*572c4311Sfengbojiang     {
478*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
479*572c4311Sfengbojiang     }
480*572c4311Sfengbojiang 
481*572c4311Sfengbojiang     /* Get the old field value. */
482*572c4311Sfengbojiang     RedisModuleString *oldval;
483*572c4311Sfengbojiang     RedisModule_HashGet(key,REDISMODULE_HASH_NONE,argv[2],&oldval,NULL);
484*572c4311Sfengbojiang     if (oldval) {
485*572c4311Sfengbojiang         RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[3],oldval,NULL);
486*572c4311Sfengbojiang     }
487*572c4311Sfengbojiang     RedisModule_ReplyWithLongLong(ctx,oldval != NULL);
488*572c4311Sfengbojiang     return REDISMODULE_OK;
489*572c4311Sfengbojiang }
490*572c4311Sfengbojiang 
491*572c4311Sfengbojiang /* HELLO.LEFTPAD str len ch
492*572c4311Sfengbojiang  * This is an implementation of the infamous LEFTPAD function, that
493*572c4311Sfengbojiang  * was at the center of an issue with the npm modules system in March 2016.
494*572c4311Sfengbojiang  *
495*572c4311Sfengbojiang  * LEFTPAD is a good example of using a Redis Modules API called
496*572c4311Sfengbojiang  * "pool allocator", that was a famous way to allocate memory in yet another
497*572c4311Sfengbojiang  * open source project, the Apache web server.
498*572c4311Sfengbojiang  *
499*572c4311Sfengbojiang  * The concept is very simple: there is memory that is useful to allocate
500*572c4311Sfengbojiang  * only in the context of serving a request, and must be freed anyway when
501*572c4311Sfengbojiang  * the callback implementing the command returns. So in that case the module
502*572c4311Sfengbojiang  * does not need to retain a reference to these allocations, it is just
503*572c4311Sfengbojiang  * required to free the memory before returning. When this is the case the
504*572c4311Sfengbojiang  * module can call RedisModule_PoolAlloc() instead, that works like malloc()
505*572c4311Sfengbojiang  * but will automatically free the memory when the module callback returns.
506*572c4311Sfengbojiang  *
507*572c4311Sfengbojiang  * Note that PoolAlloc() does not necessarily require AutoMemory to be
508*572c4311Sfengbojiang  * active. */
HelloLeftPad_RedisCommand(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)509*572c4311Sfengbojiang int HelloLeftPad_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
510*572c4311Sfengbojiang     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
511*572c4311Sfengbojiang     long long padlen;
512*572c4311Sfengbojiang 
513*572c4311Sfengbojiang     if (argc != 4) return RedisModule_WrongArity(ctx);
514*572c4311Sfengbojiang 
515*572c4311Sfengbojiang     if ((RedisModule_StringToLongLong(argv[2],&padlen) != REDISMODULE_OK) ||
516*572c4311Sfengbojiang         (padlen< 0)) {
517*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,"ERR invalid padding length");
518*572c4311Sfengbojiang     }
519*572c4311Sfengbojiang     size_t strlen, chlen;
520*572c4311Sfengbojiang     const char *str = RedisModule_StringPtrLen(argv[1], &strlen);
521*572c4311Sfengbojiang     const char *ch = RedisModule_StringPtrLen(argv[3], &chlen);
522*572c4311Sfengbojiang 
523*572c4311Sfengbojiang     /* If the string is already larger than the target len, just return
524*572c4311Sfengbojiang      * the string itself. */
525*572c4311Sfengbojiang     if (strlen >= (size_t)padlen)
526*572c4311Sfengbojiang         return RedisModule_ReplyWithString(ctx,argv[1]);
527*572c4311Sfengbojiang 
528*572c4311Sfengbojiang     /* Padding must be a single character in this simple implementation. */
529*572c4311Sfengbojiang     if (chlen != 1)
530*572c4311Sfengbojiang         return RedisModule_ReplyWithError(ctx,
531*572c4311Sfengbojiang             "ERR padding must be a single char");
532*572c4311Sfengbojiang 
533*572c4311Sfengbojiang     /* Here we use our pool allocator, for our throw-away allocation. */
534*572c4311Sfengbojiang     padlen -= strlen;
535*572c4311Sfengbojiang     char *buf = RedisModule_PoolAlloc(ctx,padlen+strlen);
536*572c4311Sfengbojiang     for (long long j = 0; j < padlen; j++) buf[j] = *ch;
537*572c4311Sfengbojiang     memcpy(buf+padlen,str,strlen);
538*572c4311Sfengbojiang 
539*572c4311Sfengbojiang     RedisModule_ReplyWithStringBuffer(ctx,buf,padlen+strlen);
540*572c4311Sfengbojiang     return REDISMODULE_OK;
541*572c4311Sfengbojiang }
542*572c4311Sfengbojiang 
543*572c4311Sfengbojiang /* This function must be present on each Redis module. It is used in order to
544*572c4311Sfengbojiang  * register the commands into the Redis server. */
RedisModule_OnLoad(RedisModuleCtx * ctx,RedisModuleString ** argv,int argc)545*572c4311Sfengbojiang int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
546*572c4311Sfengbojiang     if (RedisModule_Init(ctx,"helloworld",1,REDISMODULE_APIVER_1)
547*572c4311Sfengbojiang         == REDISMODULE_ERR) return REDISMODULE_ERR;
548*572c4311Sfengbojiang 
549*572c4311Sfengbojiang     /* Log the list of parameters passing loading the module. */
550*572c4311Sfengbojiang     for (int j = 0; j < argc; j++) {
551*572c4311Sfengbojiang         const char *s = RedisModule_StringPtrLen(argv[j],NULL);
552*572c4311Sfengbojiang         printf("Module loaded with ARGV[%d] = %s\n", j, s);
553*572c4311Sfengbojiang     }
554*572c4311Sfengbojiang 
555*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.simple",
556*572c4311Sfengbojiang         HelloSimple_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
557*572c4311Sfengbojiang         return REDISMODULE_ERR;
558*572c4311Sfengbojiang 
559*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.push.native",
560*572c4311Sfengbojiang         HelloPushNative_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
561*572c4311Sfengbojiang         return REDISMODULE_ERR;
562*572c4311Sfengbojiang 
563*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.push.call",
564*572c4311Sfengbojiang         HelloPushCall_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
565*572c4311Sfengbojiang         return REDISMODULE_ERR;
566*572c4311Sfengbojiang 
567*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.push.call2",
568*572c4311Sfengbojiang         HelloPushCall2_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
569*572c4311Sfengbojiang         return REDISMODULE_ERR;
570*572c4311Sfengbojiang 
571*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.list.sum.len",
572*572c4311Sfengbojiang         HelloListSumLen_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
573*572c4311Sfengbojiang         return REDISMODULE_ERR;
574*572c4311Sfengbojiang 
575*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.list.splice",
576*572c4311Sfengbojiang         HelloListSplice_RedisCommand,"write deny-oom",1,2,1) == REDISMODULE_ERR)
577*572c4311Sfengbojiang         return REDISMODULE_ERR;
578*572c4311Sfengbojiang 
579*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.list.splice.auto",
580*572c4311Sfengbojiang         HelloListSpliceAuto_RedisCommand,
581*572c4311Sfengbojiang         "write deny-oom",1,2,1) == REDISMODULE_ERR)
582*572c4311Sfengbojiang         return REDISMODULE_ERR;
583*572c4311Sfengbojiang 
584*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.rand.array",
585*572c4311Sfengbojiang         HelloRandArray_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
586*572c4311Sfengbojiang         return REDISMODULE_ERR;
587*572c4311Sfengbojiang 
588*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.repl1",
589*572c4311Sfengbojiang         HelloRepl1_RedisCommand,"write",0,0,0) == REDISMODULE_ERR)
590*572c4311Sfengbojiang         return REDISMODULE_ERR;
591*572c4311Sfengbojiang 
592*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.repl2",
593*572c4311Sfengbojiang         HelloRepl2_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
594*572c4311Sfengbojiang         return REDISMODULE_ERR;
595*572c4311Sfengbojiang 
596*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.toggle.case",
597*572c4311Sfengbojiang         HelloToggleCase_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
598*572c4311Sfengbojiang         return REDISMODULE_ERR;
599*572c4311Sfengbojiang 
600*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.more.expire",
601*572c4311Sfengbojiang         HelloMoreExpire_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
602*572c4311Sfengbojiang         return REDISMODULE_ERR;
603*572c4311Sfengbojiang 
604*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.zsumrange",
605*572c4311Sfengbojiang         HelloZsumRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
606*572c4311Sfengbojiang         return REDISMODULE_ERR;
607*572c4311Sfengbojiang 
608*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.lexrange",
609*572c4311Sfengbojiang         HelloLexRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
610*572c4311Sfengbojiang         return REDISMODULE_ERR;
611*572c4311Sfengbojiang 
612*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.hcopy",
613*572c4311Sfengbojiang         HelloHCopy_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
614*572c4311Sfengbojiang         return REDISMODULE_ERR;
615*572c4311Sfengbojiang 
616*572c4311Sfengbojiang     if (RedisModule_CreateCommand(ctx,"hello.leftpad",
617*572c4311Sfengbojiang         HelloLeftPad_RedisCommand,"",1,1,1) == REDISMODULE_ERR)
618*572c4311Sfengbojiang         return REDISMODULE_ERR;
619*572c4311Sfengbojiang 
620*572c4311Sfengbojiang     return REDISMODULE_OK;
621*572c4311Sfengbojiang }
622