1 extern crate redis_module;
2
3 use redis_module::native_types::RedisType;
4 use redis_module::raw::RedisModuleTypeMethods;
5
6 #[cfg(not(feature = "as-library"))]
7 use redis_module::Status;
8 #[cfg(not(feature = "as-library"))]
9 use redis_module::{Context, RedisResult};
10
11 #[cfg(not(feature = "as-library"))]
12 use crate::c_api::{
13 get_llapi_ctx, json_api_free_iter, json_api_get, json_api_get_at, json_api_get_boolean,
14 json_api_get_double, json_api_get_int, json_api_get_json, json_api_get_len,
15 json_api_get_string, json_api_get_type, json_api_is_json, json_api_len, json_api_next,
16 json_api_open_key_internal, LLAPI_CTX,
17 };
18 use crate::redisjson::Format;
19
20 mod array_index;
21 mod backward;
22 pub mod c_api;
23 pub mod commands;
24 pub mod error;
25 mod formatter;
26 pub mod ivalue_manager;
27 pub mod manager;
28 mod nodevisitor;
29 pub mod redisjson;
30
31 pub const GIT_SHA: Option<&'static str> = std::option_env!("GIT_SHA");
32 pub const GIT_BRANCH: Option<&'static str> = std::option_env!("GIT_BRANCH");
33
34 pub const REDIS_JSON_TYPE_VERSION: i32 = 3;
35
36 pub static REDIS_JSON_TYPE: RedisType = RedisType::new(
37 "ReJSON-RL",
38 REDIS_JSON_TYPE_VERSION,
39 RedisModuleTypeMethods {
40 version: redis_module::TYPE_METHOD_VERSION,
41
42 rdb_load: Some(redisjson::type_methods::rdb_load),
43 rdb_save: Some(redisjson::type_methods::rdb_save),
44 aof_rewrite: None, // TODO add support
45 free: Some(redisjson::type_methods::free),
46
47 // Currently unused by Redis
48 mem_usage: None,
49 digest: None,
50
51 // Auxiliary data (v2)
52 aux_load: None,
53 aux_save: None,
54 aux_save_triggers: 0,
55
56 free_effort: None,
57 unlink: None,
58 copy: None,
59 defrag: None,
60 },
61 );
62 /////////////////////////////////////////////////////
63
64 #[derive(Copy, Clone)]
65 pub enum ManagerType {
66 SerdeValue,
67 IValue,
68 }
69
70 pub static mut MANAGER: ManagerType = ManagerType::IValue;
71
get_manager_type() -> ManagerType72 fn get_manager_type() -> ManagerType {
73 unsafe { MANAGER }
74 }
75
76 macro_rules! run_on_manager {
77 (
78 $run:expr, $ctx:ident, $args: ident
79 ) => {
80 match $crate::get_manager_type() {
81 $crate::ManagerType::IValue => $run(
82 $crate::ivalue_manager::RedisIValueJsonKeyManager {
83 phantom: PhantomData,
84 },
85 $ctx,
86 $args,
87 ),
88 $crate::ManagerType::SerdeValue => $run(
89 $crate::manager::RedisJsonKeyManager {
90 phantom: PhantomData,
91 },
92 $ctx,
93 $args,
94 ),
95 }
96 };
97 }
98
99 #[macro_export]
100 macro_rules! redis_json_module_create {(
101 data_types: [
102 $($data_type:ident),* $(,)*
103 ],
104 pre_command_function: $pre_command_function_expr:expr,
105 get_manage: $get_manager_expr:expr,
106 version: $version:expr,
107 init: $init_func:expr,
108 ) => {
109
110 use redis_module::{redis_command, redis_module, RedisString};
111 use std::marker::PhantomData;
112 use std::os::raw::{c_double, c_int, c_longlong};
113 use redis_module::{raw as rawmod, LogLevel};
114 use rawmod::ModuleOptions;
115 use std::{
116 ffi::CStr,
117 os::raw::{c_char, c_void},
118 };
119 use libc::size_t;
120 use std::collections::HashMap;
121
122 ///
123 /// JSON.DEL <key> [path]
124 ///
125 fn json_del(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
126 $pre_command_function_expr(ctx, &args);
127 let m = $get_manager_expr;
128 match m {
129 Some(mngr) => commands::command_json_del(mngr, ctx, args),
130 None => run_on_manager!(commands::command_json_del, ctx, args),
131
132 }
133 }
134
135 ///
136 /// JSON.GET <key>
137 /// [INDENT indentation-string]
138 /// [NEWLINE line-break-string]
139 /// [SPACE space-string]
140 /// [path ...]
141 ///
142 /// TODO add support for multi path
143 fn json_get(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
144 $pre_command_function_expr(ctx, &args);
145 let m = $get_manager_expr;
146 match m {
147 Some(mngr) => commands::command_json_get(mngr, ctx, args),
148 None => run_on_manager!(commands::command_json_get, ctx, args)
149
150 }
151 }
152
153 ///
154 /// JSON.SET <key> <path> <json> [NX | XX | FORMAT <format>]
155 ///
156 fn json_set(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
157 $pre_command_function_expr(ctx, &args);
158 let m = $get_manager_expr;
159 match m {
160 Some(mngr) => commands::command_json_set(mngr, ctx, args),
161 None => run_on_manager!(commands::command_json_set, ctx, args)
162 }
163 }
164
165 ///
166 /// JSON.MGET <key> [key ...] <path>
167 ///
168 fn json_mget(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
169 $pre_command_function_expr(ctx, &args);
170 let m = $get_manager_expr;
171 match m {
172 Some(mngr) => commands::command_json_mget(mngr, ctx, args),
173 None => run_on_manager!(commands::command_json_mget, ctx, args)
174
175 }
176 }
177
178 ///
179 /// JSON.STRLEN <key> [path]
180 ///
181 fn json_str_len(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
182 $pre_command_function_expr(ctx, &args);
183 let m = $get_manager_expr;
184 match m {
185 Some(mngr) => commands::command_json_str_len(mngr, ctx, args),
186 None => run_on_manager!(commands::command_json_str_len, ctx, args)
187
188 }
189 }
190
191 ///
192 /// JSON.TYPE <key> [path]
193 ///
194 fn json_type(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
195 $pre_command_function_expr(ctx, &args);
196 let m = $get_manager_expr;
197 match m {
198 Some(mngr) => commands::command_json_type(mngr, ctx, args),
199 None => run_on_manager!(commands::command_json_type, ctx, args)
200
201 }
202 }
203
204 ///
205 /// JSON.NUMINCRBY <key> <path> <number>
206 ///
207 fn json_num_incrby(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
208 $pre_command_function_expr(ctx, &args);
209 let m = $get_manager_expr;
210 match m {
211 Some(mngr) => commands::command_json_num_incrby(mngr, ctx, args),
212 None => run_on_manager!(commands::command_json_num_incrby, ctx, args)
213
214 }
215 }
216
217 ///
218 /// JSON.NUMMULTBY <key> <path> <number>
219 ///
220 fn json_num_multby(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
221 $pre_command_function_expr(ctx, &args);
222 let m = $get_manager_expr;
223 match m {
224 Some(mngr) => commands::command_json_num_multby(mngr, ctx, args),
225 None => run_on_manager!(commands::command_json_num_multby, ctx, args)
226
227 }
228 }
229
230 ///
231 /// JSON.NUMPOWBY <key> <path> <number>
232 ///
233 fn json_num_powby(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
234 $pre_command_function_expr(ctx, &args);
235 let m = $get_manager_expr;
236 match m {
237 Some(mngr) => commands::command_json_num_powby(mngr, ctx, args),
238 None => run_on_manager!(commands::command_json_num_powby, ctx, args)
239
240 }
241 }
242
243 //
244 /// JSON.TOGGLE <key> <path>
245 fn json_bool_toggle(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
246 $pre_command_function_expr(ctx, &args);
247 let m = $get_manager_expr;
248 match m {
249 Some(mngr) => commands::command_json_bool_toggle(mngr, ctx, args),
250 None => run_on_manager!(commands::command_json_bool_toggle, ctx, args)
251
252 }
253 }
254
255 ///
256 /// JSON.STRAPPEND <key> [path] <json-string>
257 ///
258 fn json_str_append(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
259 $pre_command_function_expr(ctx, &args);
260 let m = $get_manager_expr;
261 match m {
262 Some(mngr) => commands::command_json_str_append(mngr, ctx, args),
263 None => run_on_manager!(commands::command_json_str_append, ctx, args)
264
265 }
266 }
267
268 ///
269 /// JSON.ARRAPPEND <key> <path> <json> [json ...]
270 ///
271 fn json_arr_append(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
272 $pre_command_function_expr(ctx, &args);
273 let m = $get_manager_expr;
274 match m {
275 Some(mngr) => commands::command_json_arr_append(mngr, ctx, args),
276 None => run_on_manager!(commands::command_json_arr_append, ctx, args)
277
278 }
279 }
280
281 ///
282 /// JSON.ARRINDEX <key> <path> <json-scalar> [start [stop]]
283 ///
284 /// scalar - number, string, Boolean (true or false), or null
285 ///
286 fn json_arr_index(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
287 $pre_command_function_expr(ctx, &args);
288 let m = $get_manager_expr;
289 match m {
290 Some(mngr) => commands::command_json_arr_index(mngr, ctx, args),
291 None => run_on_manager!(commands::command_json_arr_index, ctx, args)
292
293 }
294 }
295
296 ///
297 /// JSON.ARRINSERT <key> <path> <index> <json> [json ...]
298 ///
299 fn json_arr_insert(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
300 $pre_command_function_expr(ctx, &args);
301 let m = $get_manager_expr;
302 match m {
303 Some(mngr) => commands::command_json_arr_insert(mngr, ctx, args),
304 None => run_on_manager!(commands::command_json_arr_insert, ctx, args)
305 }
306 }
307
308 ///
309 /// JSON.ARRLEN <key> [path]
310 ///
311 fn json_arr_len(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
312 $pre_command_function_expr(ctx, &args);
313 let m = $get_manager_expr;
314 match m {
315 Some(mngr) => commands::command_json_arr_len(mngr, ctx, args),
316 None => run_on_manager!(commands::command_json_arr_len, ctx, args)
317
318 }
319 }
320
321 ///
322 /// JSON.ARRPOP <key> [path [index]]
323 ///
324 fn json_arr_pop(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
325 $pre_command_function_expr(ctx, &args);
326 let m = $get_manager_expr;
327 match m {
328 Some(mngr) => commands::command_json_arr_pop(mngr, ctx, args),
329 None => run_on_manager!(commands::command_json_arr_pop, ctx, args)
330
331 }
332 }
333
334 ///
335 /// JSON.ARRTRIM <key> <path> <start> <stop>
336 ///
337 fn json_arr_trim(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
338 $pre_command_function_expr(ctx, &args);
339 let m = $get_manager_expr;
340 match m {
341 Some(mngr) => commands::command_json_arr_trim(mngr, ctx, args),
342 None => run_on_manager!(commands::command_json_arr_trim, ctx, args)
343
344 }
345 }
346
347 ///
348 /// JSON.OBJKEYS <key> [path]
349 ///
350 fn json_obj_keys(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
351 $pre_command_function_expr(ctx, &args);
352 let m = $get_manager_expr;
353 match m {
354 Some(mngr) => commands::command_json_obj_keys(mngr, ctx, args),
355 None => run_on_manager!(commands::command_json_obj_keys, ctx, args)
356
357 }
358 }
359
360 ///
361 /// JSON.OBJLEN <key> [path]
362 ///
363 fn json_obj_len(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
364 $pre_command_function_expr(ctx, &args);
365 let m = $get_manager_expr;
366 match m {
367 Some(mngr) => commands::command_json_obj_len(mngr, ctx, args),
368 None => run_on_manager!(commands::command_json_obj_len, ctx, args)
369
370 }
371 }
372
373 ///
374 /// JSON.CLEAR <key> [path ...]
375 ///
376 fn json_clear(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
377 $pre_command_function_expr(ctx, &args);
378 let m = $get_manager_expr;
379 match m {
380 Some(mngr) => commands::command_json_clear(mngr, ctx, args),
381 None => run_on_manager!(commands::command_json_clear, ctx, args)
382
383 }
384 }
385
386 ///
387 /// JSON.DEBUG <subcommand & arguments>
388 ///
389 /// subcommands:
390 /// MEMORY <key> [path]
391 /// HELP
392 ///
393 fn json_debug(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
394 $pre_command_function_expr(ctx, &args);
395 let m = $get_manager_expr;
396 match m {
397 Some(mngr) => commands::command_json_debug(mngr, ctx, args),
398 None => run_on_manager!(commands::command_json_debug, ctx, args)
399
400 }
401 }
402
403 ///
404 /// JSON.RESP <key> [path]
405 ///
406 fn json_resp(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
407 $pre_command_function_expr(ctx, &args);
408 let m = $get_manager_expr;
409 match m {
410 Some(mngr) => commands::command_json_resp(mngr, ctx, args),
411 None => run_on_manager!(commands::command_json_resp, ctx, args)
412
413 }
414 }
415
416 fn json_cache_info(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
417 $pre_command_function_expr(ctx, &args);
418 let m = $get_manager_expr;
419 match m {
420 Some(mngr) => commands::command_json_cache_info(mngr, ctx, args),
421 None => run_on_manager!(commands::command_json_cache_info, ctx, args)
422
423 }
424 }
425
426 fn json_cache_init(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
427 $pre_command_function_expr(ctx, &args);
428 let m = $get_manager_expr;
429 match m {
430 Some(mngr) => commands::command_json_cache_init(mngr, ctx, args),
431 None => run_on_manager!(commands::command_json_cache_init, ctx, args)
432 }
433 }
434
435 redis_json_module_export_shared_api! {
436 get_manage:$get_manager_expr,
437 pre_command_function: $pre_command_function_expr,
438 }
439
440 fn intialize(ctx: &Context, args: &Vec<RedisString>) -> Status {
441 ctx.log_notice(&format!("version: {} git sha: {} branch: {}",
442 $version,
443 match GIT_SHA { Some(val) => val, _ => "unknown"},
444 match GIT_BRANCH { Some(val) => val, _ => "unknown"},
445 ));
446 export_shared_api(ctx);
447 ctx.set_module_options(ModuleOptions::HANDLE_IO_ERRORS);
448 ctx.log_notice("Enabled diskless replication");
449 $init_func(ctx, args)
450 }
451
452 fn json_init_config(ctx: &Context, args: &Vec<RedisString>) -> Status{
453 if args.len() % 2 != 0 {
454 ctx.log(LogLevel::Warning, "RedisJson arguments must be key:value pairs");
455 return Status::Err;
456 }
457 let mut args_map = HashMap::<String, String>::new();
458 for i in (0..args.len()).step_by(2) {
459 args_map.insert(args[i].to_string_lossy(), args[i + 1].to_string_lossy());
460 }
461
462 if let Some(backend) = args_map.get("JSON_BACKEND") {
463 if backend == "SERDE_JSON" {
464 unsafe {$crate::MANAGER = $crate::ManagerType::SerdeValue};
465 } else if backend == "IJSON" {
466 unsafe {$crate::MANAGER = $crate::ManagerType::IValue};
467 } else {
468 ctx.log(LogLevel::Warning, "Unsupported json backend was given");
469 return Status::Err;
470 }
471 }
472
473 Status::Ok
474 }
475
476 redis_module! {
477 name: "ReJSON",
478 version: $version,
479 data_types: [$($data_type,)*],
480 init: json_init_config,
481 init: intialize,
482 commands: [
483 ["json.del", json_del, "write", 1,1,1],
484 ["json.get", json_get, "readonly", 1,1,1],
485 ["json.mget", json_mget, "readonly", 1,1,1],
486 ["json.set", json_set, "write deny-oom", 1,1,1],
487 ["json.type", json_type, "readonly", 1,1,1],
488 ["json.numincrby", json_num_incrby, "write", 1,1,1],
489 ["json.toggle", json_bool_toggle, "write deny-oom", 1,1,1],
490 ["json.nummultby", json_num_multby, "write", 1,1,1],
491 ["json.numpowby", json_num_powby, "write", 1,1,1],
492 ["json.strappend", json_str_append, "write deny-oom", 1,1,1],
493 ["json.strlen", json_str_len, "readonly", 1,1,1],
494 ["json.arrappend", json_arr_append, "write deny-oom", 1,1,1],
495 ["json.arrindex", json_arr_index, "readonly", 1,1,1],
496 ["json.arrinsert", json_arr_insert, "write deny-oom", 1,1,1],
497 ["json.arrlen", json_arr_len, "readonly", 1,1,1],
498 ["json.arrpop", json_arr_pop, "write", 1,1,1],
499 ["json.arrtrim", json_arr_trim, "write", 1,1,1],
500 ["json.objkeys", json_obj_keys, "readonly", 1,1,1],
501 ["json.objlen", json_obj_len, "readonly", 1,1,1],
502 ["json.clear", json_clear, "write", 1,1,1],
503 ["json.debug", json_debug, "readonly", 2,2,1],
504 ["json.forget", json_del, "write", 1,1,1],
505 ["json.resp", json_resp, "readonly", 1,1,1],
506 ["json._cacheinfo", json_cache_info, "readonly", 1,1,1],
507 ["json._cacheinit", json_cache_init, "write", 1,1,1],
508 ],
509 }
510 }
511 }
512
513 #[cfg(not(feature = "as-library"))]
pre_command(_ctx: &Context, _args: &Vec<RedisString>)514 fn pre_command(_ctx: &Context, _args: &Vec<RedisString>) {}
515
516 #[cfg(not(feature = "as-library"))]
dummy_init(_ctx: &Context, _args: &Vec<RedisString>) -> Status517 fn dummy_init(_ctx: &Context, _args: &Vec<RedisString>) -> Status {
518 Status::Ok
519 }
520
521 #[cfg(not(feature = "as-library"))]
522 redis_json_module_create! {
523 data_types: [REDIS_JSON_TYPE],
524 pre_command_function: pre_command,
525 get_manage: {
526 match get_manager_type() {
527 ManagerType::IValue => Some(ivalue_manager::RedisIValueJsonKeyManager{phantom:PhantomData}),
528 _ => None,
529 }
530 },
531 version: 02_00_06,
532 init: dummy_init,
533 }
534