redis_simd_json/
lib.rs

1//!
2//! Optimized Redis GET / MGET / SET / MSET commands utilizing SIMD JSON with NodeJS [bindings](https://www.npmjs.com/package/redis-simd-json)
3
4use napi::bindgen_prelude::*;
5use napi_derive::napi;
6use redis::AsyncCommands;
7use redis_swapplex::get_connection;
8use serde_json::Value;
9
10#[napi]
11/// Get the deserialized value of a key
12pub async fn get(key: String) -> Result<Option<Value>> {
13  let mut conn = get_connection();
14
15  let bytes: Option<Vec<u8>> = conn
16    .get(key)
17    .await
18    .map_err(|err| Error::new(Status::GenericFailure, format!("{:?}", err)))?;
19
20  if let Some(mut bytes) = bytes {
21    let value: Value = simd_json::serde::from_slice(bytes.as_mut_slice())
22      .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
23
24    Ok(Some(value))
25  } else {
26    Ok(None)
27  }
28}
29
30#[napi]
31/// Get the deserialized values of a set of keys
32pub async fn mget(keys: Vec<String>) -> Result<Vec<Option<Value>>> {
33  let mut conn = get_connection();
34
35  let data: Vec<Option<Vec<u8>>> = redis::cmd("MGET")
36    .arg(&keys)
37    .query_async(&mut conn)
38    .await
39    .map_err(|err| Error::new(Status::GenericFailure, format!("{:?}", err)))?;
40
41  data
42    .into_iter()
43    .map(|bytes| {
44      if let Some(mut bytes) = bytes {
45        let value = simd_json::serde::from_slice(bytes.as_mut_slice())
46          .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
47
48        Ok(Some(value))
49      } else {
50        Ok(None)
51      }
52    })
53    .collect::<Result<Vec<Option<Value>>>>()
54}
55
56#[napi]
57/// Serialize and set the value at a key
58pub async fn set(key: String, value: Option<Value>) -> Result<()> {
59  let value = match value {
60    Some(value) => Some(
61      simd_json::to_vec(&value)
62        .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?,
63    ),
64    None => None,
65  };
66
67  let mut conn = get_connection();
68
69  let _: () = conn
70    .set(key, value)
71    .await
72    .map_err(|err| Error::new(Status::GenericFailure, format!("{:?}", err)))?;
73
74  Ok(())
75}
76
77#[napi]
78/// Serialize and set the value at a key if the current value hasn't changed. Returns count of modified keys. Requires that [redis-cas](https://github.com/Bajix/redis-cas) is loaded on Redis
79pub async fn compare_and_swap(key: String, current: Value, value: Option<Value>) -> Result<i64> {
80  let current = simd_json::to_vec(&current)
81    .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
82
83  let value = match value {
84    Some(value) => simd_json::to_vec(&value)
85      .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?,
86
87    None => vec![],
88  };
89
90  let mut conn = get_connection();
91
92  let n_modified: i64 = redis::cmd("CAS")
93    .arg(&[key.as_bytes(), &current, &value])
94    .query_async(&mut conn)
95    .await
96    .map_err(|err| Error::new(Status::GenericFailure, format!("{:?}", err)))?;
97
98  Ok(n_modified)
99}
100
101#[napi]
102/// Serialize and set the values of multiple keys
103pub async fn mset(data: Vec<(String, Option<Value>)>) -> Result<()> {
104  let data = data
105    .into_iter()
106    .map(|(key, value)| match value {
107      Some(value) => {
108        let bytes: Vec<u8> = simd_json::to_vec(&value)
109          .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
110
111        Ok((key, Some(bytes)))
112      }
113      None => Ok((key, None)),
114    })
115    .collect::<Result<Vec<(String, Option<Vec<u8>>)>>>()?;
116
117  let mut conn = get_connection();
118
119  let _: () = redis::cmd("MSET")
120    .arg(&data[..])
121    .query_async(&mut conn)
122    .await
123    .map_err(|err| Error::new(Status::GenericFailure, format!("{:?}", err)))?;
124
125  Ok(())
126}