11#[ macro_use]
22extern crate redismodule;
33
4- use redismodule:: { Context , RedisResult , NextArg , REDIS_OK , RedisError } ;
54use redismodule:: native_types:: RedisType ;
5+ use redismodule:: { Context , NextArg , RedisError , RedisResult , REDIS_OK } ;
66
77mod redisjson;
88
9- use crate :: redisjson:: RedisJSON ;
9+ use crate :: redisjson:: { Error , RedisJSON } ;
1010
1111static REDIS_JSON_TYPE : RedisType = RedisType :: new ( "RedisJSON" ) ;
1212
@@ -25,7 +25,7 @@ fn json_del(ctx: &Context, args: Vec<String>) -> RedisResult {
2525 let key = ctx. open_key_writable ( & key) ;
2626 let deleted = match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
2727 Some ( doc) => doc. delete_path ( & path) ?,
28- None => 0
28+ None => 0 ,
2929 } ;
3030 Ok ( deleted. into ( ) )
3131}
@@ -37,13 +37,12 @@ fn json_set(ctx: &Context, args: Vec<String>) -> RedisResult {
3737 let path = args. next_string ( ) ?;
3838 let value = args. next_string ( ) ?;
3939
40- let set_option = args. next ( )
41- . map ( |op| {
42- match op. to_uppercase ( ) . as_str ( ) {
43- "NX" => Ok ( SetOptions :: NotExists ) ,
44- "XX" => Ok ( SetOptions :: AlreadyExists ) ,
45- _ => Err ( RedisError :: Str ( "ERR syntax error" ) ) ,
46- }
40+ let set_option = args
41+ . next ( )
42+ . map ( |op| match op. to_uppercase ( ) . as_str ( ) {
43+ "NX" => Ok ( SetOptions :: NotExists ) ,
44+ "XX" => Ok ( SetOptions :: AlreadyExists ) ,
45+ _ => Err ( RedisError :: Str ( "ERR syntax error" ) ) ,
4746 } )
4847 . transpose ( ) ?;
4948
@@ -73,63 +72,62 @@ fn json_get(ctx: &Context, args: Vec<String>) -> RedisResult {
7372 let mut path = loop {
7473 let arg = match args. next_string ( ) {
7574 Ok ( s) => s,
76- Err ( _) => "$" . to_owned ( ) // path is optional
75+ Err ( _) => "$" . to_owned ( ) , // path is optional
7776 } ;
7877
7978 match arg. as_str ( ) {
80- "INDENT" => args. next ( ) , // TODO add support
81- "NEWLINE" => args. next ( ) , // TODO add support
82- "SPACE" => args. next ( ) , // TODO add support
83- "NOESCAPE" => continue , // TODO add support
84- "." => break String :: from ( "$" ) , // backward compatibility suuport
85- _ => break arg
79+ "INDENT" => args. next ( ) , // TODO add support
80+ "NEWLINE" => args. next ( ) , // TODO add support
81+ "SPACE" => args. next ( ) , // TODO add support
82+ "NOESCAPE" => continue , // TODO add support
83+ "." => break String :: from ( "$" ) , // backward compatibility support
84+ _ => break arg,
8685 } ;
8786 } ;
8887
89- if path. starts_with ( "." ) { // backward compatibility
88+ if path. starts_with ( "." ) {
89+ // backward compatibility
9090 path. insert ( 0 , '$' ) ;
9191 }
9292
9393 let key = ctx. open_key_writable ( & key) ;
9494
9595 let value = match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
9696 Some ( doc) => doc. to_string ( & path) ?. into ( ) ,
97- None => ( ) . into ( )
97+ None => ( ) . into ( ) ,
9898 } ;
9999
100100 Ok ( value)
101101}
102102
103103fn json_mget ( ctx : & Context , args : Vec < String > ) -> RedisResult {
104-
105104 if args. len ( ) < 3 {
106105 return Err ( RedisError :: WrongArity ) ;
107106 }
108107 if let Some ( path) = args. last ( ) {
109108 let mut path = path. clone ( ) ;
110- if path. starts_with ( "." ) { // backward compatibility
109+ if path. starts_with ( "." ) {
110+ // backward compatibility
111111 path. insert ( 0 , '$' ) ;
112112 }
113- let mut results: Vec < String > = Vec :: with_capacity ( args. len ( ) - 2 ) ;
114- for key in & args[ 1 ..args. len ( ) - 1 ] {
113+ let mut results: Vec < String > = Vec :: with_capacity ( args. len ( ) - 2 ) ;
114+ for key in & args[ 1 ..args. len ( ) - 1 ] {
115115 let redis_key = ctx. open_key_writable ( & key) ;
116116 match redis_key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
117117 Some ( doc) => {
118118 let result = doc. to_string ( & path) ?;
119119 results. push ( result) ;
120- } ,
120+ }
121121 None => { }
122122 } ;
123-
124123 }
125124 Ok ( results. into ( ) )
126125 } else {
127126 Err ( RedisError :: WrongArity )
128127 }
129128}
130129
131-
132- fn json_strlen ( ctx : & Context , args : Vec < String > ) -> RedisResult {
130+ fn json_str_len ( ctx : & Context , args : Vec < String > ) -> RedisResult {
133131 let mut args = args. into_iter ( ) . skip ( 1 ) ;
134132 let key = args. next_string ( ) ?;
135133 let path = args. next_string ( ) ?;
@@ -138,7 +136,7 @@ fn json_strlen(ctx: &Context, args: Vec<String>) -> RedisResult {
138136
139137 let length = match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
140138 Some ( doc) => doc. str_len ( & path) ?. into ( ) ,
141- None => ( ) . into ( )
139+ None => ( ) . into ( ) ,
142140 } ;
143141
144142 Ok ( length)
@@ -153,12 +151,107 @@ fn json_type(ctx: &Context, args: Vec<String>) -> RedisResult {
153151
154152 let value = match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
155153 Some ( doc) => doc. get_type ( & path) ?. into ( ) ,
156- None => ( ) . into ( )
154+ None => ( ) . into ( ) ,
157155 } ;
158156
159157 Ok ( value)
160158}
161159
160+ fn json_num_incrby ( ctx : & Context , args : Vec < String > ) -> RedisResult {
161+ json_num_op ( ctx, args, |num1, num2| num1 + num2)
162+ }
163+
164+ fn json_num_multby ( ctx : & Context , args : Vec < String > ) -> RedisResult {
165+ json_num_op ( ctx, args, |num1, num2| num1 * num2)
166+ }
167+
168+ fn json_num_powby ( ctx : & Context , args : Vec < String > ) -> RedisResult {
169+ json_num_op ( ctx, args, |num1, num2| num1. powf ( num2) )
170+ }
171+
172+ fn json_num_op < F > ( ctx : & Context , args : Vec < String > , fun : F ) -> RedisResult
173+ where F : Fn ( f64 , f64 ) -> f64 {
174+ let mut args = args. into_iter ( ) . skip ( 1 ) ;
175+
176+ let key = args. next_string ( ) ?;
177+ let path = args. next_string ( ) ?;
178+ let number: f64 = args. next_string ( ) ?. parse ( ) ?;
179+
180+ let key = ctx. open_key_writable ( & key) ;
181+
182+ match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
183+ Some ( doc) => Ok ( doc. num_op ( & path, number, fun) ?. into ( ) ) ,
184+ None => Err ( "ERR could not perform this operation on a key that doesn't exist" . into ( ) ) ,
185+ }
186+ }
187+
188+ fn json_str_append ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
189+ Err ( "Command was not implemented" . into ( ) )
190+ }
191+
192+ fn json_arr_append ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
193+ Err ( "Command was not implemented" . into ( ) )
194+ }
195+
196+ fn json_arr_index ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
197+ Err ( "Command was not implemented" . into ( ) )
198+ }
199+
200+ fn json_arr_insert ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
201+ Err ( "Command was not implemented" . into ( ) )
202+ }
203+
204+ fn json_arr_len ( ctx : & Context , args : Vec < String > ) -> RedisResult {
205+ json_len ( ctx, args, |doc, path| doc. arr_len ( path) )
206+ }
207+
208+ fn json_arr_pop ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
209+ Err ( "Command was not implemented" . into ( ) )
210+ }
211+
212+ fn json_arr_trim ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
213+ Err ( "Command was not implemented" . into ( ) )
214+ }
215+
216+ fn json_obj_keys ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
217+ Err ( "Command was not implemented" . into ( ) )
218+ }
219+
220+ fn json_obj_len ( ctx : & Context , args : Vec < String > ) -> RedisResult {
221+ json_len ( ctx, args, |doc, path| doc. obj_len ( path) )
222+ }
223+
224+ fn json_debug ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
225+ Err ( "Command was not implemented" . into ( ) )
226+ }
227+
228+ fn json_forget ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
229+ Err ( "Command was not implemented" . into ( ) )
230+ }
231+
232+ fn json_resp ( _ctx : & Context , _args : Vec < String > ) -> RedisResult {
233+ Err ( "Command was not implemented" . into ( ) )
234+ }
235+
236+ fn json_len < F : Fn ( & RedisJSON , & String ) -> Result < usize , Error > > (
237+ ctx : & Context ,
238+ args : Vec < String > ,
239+ fun : F ,
240+ ) -> RedisResult {
241+ let mut args = args. into_iter ( ) . skip ( 1 ) ;
242+ let key = args. next_string ( ) ?;
243+ let path = args. next_string ( ) ?;
244+
245+ let key = ctx. open_key_writable ( & key) ;
246+
247+ let length = match key. get_value :: < RedisJSON > ( & REDIS_JSON_TYPE ) ? {
248+ Some ( doc) => fun ( & doc, & path) ?. into ( ) ,
249+ None => ( ) . into ( ) ,
250+ } ;
251+
252+ Ok ( length)
253+ }
254+
162255//////////////////////////////////////////////////////
163256
164257redis_module ! {
@@ -168,11 +261,26 @@ redis_module! {
168261 REDIS_JSON_TYPE ,
169262 ] ,
170263 commands: [
171- [ "json.set" , json_set, "write" ] ,
172264 [ "json.del" , json_del, "write" ] ,
173265 [ "json.get" , json_get, "" ] ,
174266 [ "json.mget" , json_mget, "" ] ,
175- [ "json.strlen " , json_strlen , "" ] ,
267+ [ "json.set " , json_set , "write " ] ,
176268 [ "json.type" , json_type, "" ] ,
269+ [ "json.numincrby" , json_num_incrby, "" ] ,
270+ [ "json.nummultby" , json_num_multby, "" ] ,
271+ [ "json.numpowby" , json_num_powby, "" ] ,
272+ [ "json.strappend" , json_str_append, "" ] ,
273+ [ "json.strlen" , json_str_len, "" ] ,
274+ [ "json.arrappend" , json_arr_append, "" ] ,
275+ [ "json.arrindex" , json_arr_index, "" ] ,
276+ [ "json.arrinsert" , json_arr_insert, "" ] ,
277+ [ "json.arrlen" , json_arr_len, "" ] ,
278+ [ "json.arrpop" , json_arr_pop, "" ] ,
279+ [ "json.arrtrim" , json_arr_trim, "" ] ,
280+ [ "json.objkeys" , json_obj_keys, "" ] ,
281+ [ "json.objlen" , json_obj_len, "" ] ,
282+ [ "json.debug" , json_debug, "" ] ,
283+ [ "json.forget" , json_forget, "" ] ,
284+ [ "json.resp" , json_resp, "" ] ,
177285 ] ,
178286}
0 commit comments