1use js_sys::{ArrayBuffer, Function, Object, Promise, Uint8Array};
2use serde::{de::DeserializeOwned, Serialize};
3use serde_json::Value;
4use serde_wasm_bindgen::Serializer;
5use wasm_bindgen::{JsCast, JsValue};
6use wasm_bindgen_futures::JsFuture;
7
8use crate::{KvError, ListResponse};
9
10#[derive(Debug, Clone)]
12#[must_use = "PutOptionsBuilder does nothing until you 'execute' it"]
13pub struct PutOptionsBuilder {
14 pub(crate) this: Object,
15 pub(crate) put_function: Function,
16 pub(crate) name: JsValue,
17 pub(crate) value: JsValue,
18 pub(crate) expiration: Option<u64>,
19 pub(crate) expiration_ttl: Option<u64>,
20 pub(crate) metadata: Option<Value>,
21}
22
23#[derive(Serialize)]
24struct PutOptions {
25 #[serde(skip_serializing_if = "Option::is_none")]
26 expiration: Option<u64>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 #[serde(rename = "expirationTtl")]
29 expiration_ttl: Option<u64>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 metadata: Option<Value>,
32}
33
34impl PutOptionsBuilder {
35 pub fn expiration(mut self, expiration: u64) -> Self {
38 self.expiration = Some(expiration);
39 self
40 }
41 pub fn expiration_ttl(mut self, expiration_ttl: u64) -> Self {
43 self.expiration_ttl = Some(expiration_ttl);
44 self
45 }
46 pub fn metadata<T: Serialize>(mut self, metadata: T) -> Result<Self, KvError> {
48 self.metadata = Some(serde_json::to_value(metadata)?);
49 Ok(self)
50 }
51 pub async fn execute(self) -> Result<(), KvError> {
53 let ser = Serializer::json_compatible();
54 let options_object = PutOptions {
55 expiration: self.expiration,
56 expiration_ttl: self.expiration_ttl,
57 metadata: self.metadata,
58 }
59 .serialize(&ser)
60 .map_err(JsValue::from)?;
61
62 let promise: Promise = self
63 .put_function
64 .call3(&self.this, &self.name, &self.value, &options_object)?
65 .into();
66 JsFuture::from(promise)
67 .await
68 .map(|_| ())
69 .map_err(KvError::from)
70 }
71}
72
73#[derive(Debug, Clone)]
75#[must_use = "ListOptionsBuilder does nothing until you 'execute' it"]
76pub struct ListOptionsBuilder {
77 pub(crate) this: Object,
78 pub(crate) list_function: Function,
79 pub(crate) limit: Option<u64>,
80 pub(crate) cursor: Option<String>,
81 pub(crate) prefix: Option<String>,
82}
83
84#[derive(Serialize)]
85struct ListOptions {
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub(crate) limit: Option<u64>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub(crate) cursor: Option<String>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub(crate) prefix: Option<String>,
92}
93
94impl ListOptionsBuilder {
95 pub fn limit(mut self, limit: u64) -> Self {
98 self.limit = Some(limit);
99 self
100 }
101 pub fn cursor(mut self, cursor: String) -> Self {
103 self.cursor = Some(cursor);
104 self
105 }
106 pub fn prefix(mut self, prefix: String) -> Self {
108 self.prefix = Some(prefix);
109 self
110 }
111 pub async fn execute(self) -> Result<ListResponse, KvError> {
113 let ser = Serializer::json_compatible();
114 let options_object = ListOptions {
115 limit: self.limit,
116 cursor: self.cursor,
117 prefix: self.prefix,
118 }
119 .serialize(&ser)
120 .map_err(JsValue::from)?;
121
122 let promise: Promise = self
123 .list_function
124 .call1(&self.this, &options_object)?
125 .into();
126
127 let value = JsFuture::from(promise).await?;
128 let resp = serde_wasm_bindgen::from_value(value).map_err(JsValue::from)?;
129 Ok(resp)
130 }
131}
132
133#[derive(Debug, Clone)]
135#[must_use = "GetOptionsBuilder does nothing until you 'get' it"]
136pub struct GetOptionsBuilder {
137 pub(crate) this: Object,
138 pub(crate) get_function: Function,
139 pub(crate) get_with_meta_function: Function,
140 pub(crate) name: JsValue,
141 pub(crate) cache_ttl: Option<u64>,
142 pub(crate) value_type: Option<GetValueType>,
143}
144
145#[derive(Serialize)]
146struct GetOptions {
147 #[serde(rename = "cacheTtl", skip_serializing_if = "Option::is_none")]
148 pub(crate) cache_ttl: Option<u64>,
149 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
150 pub(crate) value_type: Option<GetValueType>,
151}
152
153impl GetOptionsBuilder {
154 pub fn cache_ttl(mut self, cache_ttl: u64) -> Self {
162 self.cache_ttl = Some(cache_ttl);
163 self
164 }
165
166 fn value_type(mut self, value_type: GetValueType) -> Self {
167 self.value_type = Some(value_type);
168 self
169 }
170
171 fn options(&self) -> Result<JsValue, KvError> {
172 let ser = Serializer::json_compatible();
173 Ok(GetOptions {
174 cache_ttl: self.cache_ttl,
175 value_type: self.value_type,
176 }
177 .serialize(&ser)
178 .map_err(JsValue::from)?)
179 }
180
181 async fn get(self) -> Result<JsValue, KvError> {
182 let options_object = self.options()?;
183
184 let promise: Promise = self
185 .get_function
186 .call2(&self.this, &self.name, &options_object)?
187 .into();
188 JsFuture::from(promise).await.map_err(KvError::from)
189 }
190
191 pub async fn text(self) -> Result<Option<String>, KvError> {
193 let value = self.value_type(GetValueType::Text).get().await?;
194 Ok(value.as_string())
195 }
196
197 pub async fn json<T>(self) -> Result<Option<T>, KvError>
199 where
200 T: DeserializeOwned,
201 {
202 let value = self.value_type(GetValueType::Json).get().await?;
203 Ok(if value.is_null() {
204 None
205 } else {
206 Some(serde_wasm_bindgen::from_value(value).map_err(JsValue::from)?)
207 })
208 }
209
210 pub async fn bytes(self) -> Result<Option<Vec<u8>>, KvError> {
212 let v = self.value_type(GetValueType::ArrayBuffer).get().await?;
213 if ArrayBuffer::instanceof(&v) {
214 let buffer = ArrayBuffer::from(v);
215 let buffer = Uint8Array::new(&buffer);
216 Ok(Some(buffer.to_vec()))
217 } else {
218 Ok(None)
219 }
220 }
221
222 async fn get_with_metadata<M>(&self) -> Result<(JsValue, Option<M>), KvError>
223 where
224 M: DeserializeOwned,
225 {
226 let options_object = self.options()?;
227
228 let promise: Promise = self
229 .get_with_meta_function
230 .call2(&self.this, &self.name, &options_object)?
231 .into();
232
233 let pair = JsFuture::from(promise).await?;
234 let metadata = crate::get(&pair, "metadata")?;
235 let value = crate::get(&pair, "value")?;
236
237 Ok((
238 value,
239 if metadata.is_null() {
240 None
241 } else {
242 Some(serde_wasm_bindgen::from_value(metadata).map_err(JsValue::from)?)
243 },
244 ))
245 }
246
247 pub async fn text_with_metadata<M>(self) -> Result<(Option<String>, Option<M>), KvError>
249 where
250 M: DeserializeOwned,
251 {
252 let (value, metadata) = self
253 .value_type(GetValueType::Text)
254 .get_with_metadata()
255 .await?;
256 Ok((value.as_string(), metadata))
257 }
258
259 pub async fn json_with_metadata<T, M>(self) -> Result<(Option<T>, Option<M>), KvError>
261 where
262 T: DeserializeOwned,
263 M: DeserializeOwned,
264 {
265 let (value, metadata) = self
266 .value_type(GetValueType::Json)
267 .get_with_metadata()
268 .await?;
269 Ok((
270 if value.is_null() {
271 None
272 } else {
273 Some(serde_wasm_bindgen::from_value(value).map_err(JsValue::from)?)
274 },
275 metadata,
276 ))
277 }
278
279 pub async fn bytes_with_metadata<M>(self) -> Result<(Option<Vec<u8>>, Option<M>), KvError>
281 where
282 M: DeserializeOwned,
283 {
284 let (value, metadata) = self
285 .value_type(GetValueType::ArrayBuffer)
286 .get_with_metadata()
287 .await?;
288
289 if ArrayBuffer::instanceof(&value) {
290 let buffer = ArrayBuffer::from(value);
291 let buffer = Uint8Array::new(&buffer);
292 Ok((Some(buffer.to_vec()), metadata))
293 } else {
294 Ok((None, metadata))
295 }
296 }
297}
298
299#[derive(Debug, Clone, Serialize, Copy)]
300#[serde(rename_all = "camelCase")]
301pub(crate) enum GetValueType {
302 Text,
303 ArrayBuffer,
304 Json,
305}