1use {
2 crate::wiggle_abi::types::{FastlyStatus, KvError, KvInsertMode},
3 base64::prelude::*,
4 serde::Serialize,
5 std::{
6 collections::BTreeMap,
7 sync::{Arc, RwLock},
8 time::SystemTime,
9 },
10};
11
12#[derive(Debug, Clone)]
13pub struct ObjectValue {
14 pub body: Vec<u8>,
15 pub metadata: String,
16 pub metadata_len: usize,
17 pub generation: u64,
18 pub expiration: Option<SystemTime>,
19}
20
21#[derive(Clone, Debug, Default)]
22pub struct ObjectStores {
23 #[allow(clippy::type_complexity)]
24 stores: Arc<RwLock<BTreeMap<ObjectStoreKey, BTreeMap<ObjectKey, ObjectValue>>>>,
25}
26
27impl ObjectStores {
28 pub fn new() -> Self {
29 Self {
30 stores: Arc::new(RwLock::new(BTreeMap::new())),
31 }
32 }
33
34 pub(crate) fn store_exists(&self, obj_store_key: &str) -> Result<bool, ObjectStoreError> {
35 Ok(self
36 .stores
37 .read()
38 .map_err(|_| ObjectStoreError::PoisonedLock)?
39 .get(&ObjectStoreKey::new(obj_store_key))
40 .is_some())
41 }
42
43 pub fn lookup(
44 &self,
45 obj_store_key: ObjectStoreKey,
46 obj_key: ObjectKey,
47 ) -> Result<Option<ObjectValue>, KvStoreError> {
48 let mut res = Ok(None);
49
50 self.stores
51 .write()
52 .map_err(|_| KvStoreError::InternalError)?
53 .entry(obj_store_key)
54 .and_modify(|store| match store.get(&obj_key) {
55 Some(val) => {
56 res = Ok(Some(val.clone()));
57 if let Some(exp) = val.expiration {
59 if SystemTime::now() >= exp {
60 store.remove(&obj_key);
61 res = Ok(None);
62 }
63 }
64 }
65 None => {
66 res = Ok(None);
67 }
68 });
69
70 res
71 }
72
73 pub(crate) fn insert_empty_store(
74 &self,
75 obj_store_key: ObjectStoreKey,
76 ) -> Result<(), ObjectStoreError> {
77 self.stores
78 .write()
79 .map_err(|_| ObjectStoreError::PoisonedLock)?
80 .entry(obj_store_key)
81 .and_modify(|_| {})
82 .or_insert_with(BTreeMap::new);
83
84 Ok(())
85 }
86
87 pub fn insert(
88 &self,
89 obj_store_key: ObjectStoreKey,
90 obj_key: ObjectKey,
91 obj: Vec<u8>,
92 mode: KvInsertMode,
93 generation: Option<u64>,
94 metadata: Option<String>,
95 ttl: Option<std::time::Duration>,
96 ) -> Result<(), KvStoreError> {
97 let existing = self
99 .lookup(obj_store_key.clone(), obj_key.clone())
100 .map_err(|_| KvStoreError::InternalError)?;
101
102 if let Some(g) = generation {
103 if let Some(val) = &existing {
104 if val.generation != g {
105 return Err(KvStoreError::PreconditionFailed);
106 }
107 }
108 }
109
110 let out_obj = match mode {
111 KvInsertMode::Overwrite => obj,
112 KvInsertMode::Add => {
113 if existing.is_some() {
114 return Err(KvStoreError::PreconditionFailed);
116 }
117 obj
118 }
119 KvInsertMode::Append => {
120 let mut out_obj;
121 match existing {
122 None => {
123 out_obj = obj;
124 }
125 Some(v) => {
126 out_obj = v.body;
127 out_obj.append(&mut obj.clone());
128 }
129 }
130 out_obj
131 }
132 KvInsertMode::Prepend => {
133 let mut out_obj;
134 match existing {
135 None => {
136 out_obj = obj;
137 }
138 Some(mut v) => {
139 out_obj = obj;
140 out_obj.append(&mut v.body);
141 }
142 }
143 out_obj
144 }
145 };
146
147 let exp = ttl.map(|t| SystemTime::now() + t);
148
149 let mut obj_val = ObjectValue {
150 body: out_obj,
151 metadata: String::new(),
152 metadata_len: 0,
153 generation: SystemTime::now()
154 .duration_since(SystemTime::UNIX_EPOCH)
155 .unwrap()
156 .as_nanos() as u64,
157 expiration: exp,
158 };
159
160 if obj_val.generation == 1337 {
162 obj_val.generation = 1338;
163 }
164
165 if let Some(m) = metadata {
166 obj_val.metadata_len = m.len();
167 obj_val.metadata = m;
168 }
169
170 self.stores
171 .write()
172 .map_err(|_| KvStoreError::InternalError)?
173 .entry(obj_store_key)
174 .and_modify(|store| {
175 store.insert(obj_key.clone(), obj_val.clone());
176 })
177 .or_insert_with(|| {
178 let mut store = BTreeMap::new();
179 store.insert(obj_key, obj_val);
180 store
181 });
182
183 Ok(())
184 }
185
186 pub fn delete(
187 &self,
188 obj_store_key: ObjectStoreKey,
189 obj_key: ObjectKey,
190 ) -> Result<bool, KvStoreError> {
191 let mut res = Ok(true);
192
193 self.stores
194 .write()
195 .map_err(|_| KvStoreError::InternalError)?
196 .entry(obj_store_key)
197 .and_modify(|store| match store.get(&obj_key) {
198 Some(val) => {
200 if let Some(exp) = val.expiration {
202 if SystemTime::now() >= exp {
203 res = Ok(false);
204 }
205 }
206 store.remove(&obj_key);
207 }
208 None => res = Ok(false),
209 });
210
211 res
212 }
213
214 pub fn list(
215 &self,
216 obj_store_key: ObjectStoreKey,
217 cursor: Option<String>,
218 prefix: Option<String>,
219 limit: u32,
220 ) -> Result<Vec<u8>, KvStoreError> {
221 let mut res = Err(KvStoreError::InternalError);
222
223 let cursor = match cursor {
224 Some(c) => {
225 let cursor_bytes = BASE64_STANDARD
226 .decode(c)
227 .map_err(|_| KvStoreError::BadRequest)?;
228 let decoded =
229 String::from_utf8(cursor_bytes).map_err(|_| KvStoreError::BadRequest)?;
230 Some(decoded)
231 }
232 None => None,
233 };
234
235 self.stores
236 .write()
237 .map_err(|_| KvStoreError::InternalError)?
238 .entry(obj_store_key.clone())
239 .and_modify(|store| {
240 let ttl_list = store.iter_mut().map(|(k, _)| k.clone()).collect::<Vec<_>>();
244 ttl_list.into_iter().for_each(|k| {
245 let val = store.get(&k);
246 if let Some(v) = val {
247 if let Some(exp) = v.expiration {
248 if SystemTime::now() >= exp {
249 store.remove(&k);
250 }
251 }
252 }
253 });
254
255 let mut list = store
256 .iter_mut()
257 .filter(|(k, _)| {
258 if let Some(c) = &cursor {
259 &k.0 > c
260 } else {
261 true
262 }
263 })
264 .filter(|(k, _)| {
265 if let Some(p) = &prefix {
266 k.0.starts_with(p)
267 } else {
268 true
269 }
270 })
271 .map(|(k, _)| String::from_utf8(k.0.as_bytes().to_vec()).unwrap())
272 .collect::<Vec<_>>();
273
274 let old_len = list.len();
276 list.truncate(limit as usize);
277 let new_len = list.len();
278
279 let next_cursor = match old_len != new_len {
280 true => Some(BASE64_STANDARD.encode(&list[new_len - 1])),
281 false => None,
282 };
283
284 #[derive(Serialize)]
285 struct Metadata {
286 limit: u32,
287 #[serde(skip_serializing_if = "Option::is_none")]
288 prefix: Option<String>,
289 #[serde(skip_serializing_if = "Option::is_none")]
290 next_cursor: Option<String>,
291 }
292 #[derive(Serialize)]
293 struct JsonOutput {
294 data: Vec<String>,
295 meta: Metadata,
296 }
297
298 let body = JsonOutput {
299 data: list,
300 meta: Metadata {
301 limit,
302 prefix,
303 next_cursor,
304 },
305 };
306
307 match serde_json::to_string(&body).map_err(|_| KvStoreError::InternalError) {
308 Ok(s) => res = Ok(s.as_bytes().to_vec()),
309 Err(e) => res = Err(e),
310 };
311 });
312 res
313 }
314}
315
316#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Default)]
317pub struct ObjectStoreKey(String);
318
319impl ObjectStoreKey {
320 pub fn new(key: impl ToString) -> Self {
321 Self(key.to_string())
322 }
323}
324
325#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Default)]
326pub struct ObjectKey(String);
327
328impl ObjectKey {
329 pub fn new(key: impl ToString) -> Result<Self, KeyValidationError> {
330 let key = key.to_string();
331 is_valid_key(&key)?;
332 Ok(Self(key))
333 }
334}
335
336#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, thiserror::Error)]
337pub enum ObjectStoreError {
338 #[error("The object was not in the store")]
339 MissingObject,
340 #[error("Viceroy's ObjectStore lock was poisoned")]
341 PoisonedLock,
342 #[error("Unknown object-store: {0}")]
344 UnknownObjectStore(String),
345}
346
347impl From<&ObjectStoreError> for FastlyStatus {
348 fn from(e: &ObjectStoreError) -> Self {
349 use ObjectStoreError::*;
350 match e {
351 MissingObject => FastlyStatus::None,
352 PoisonedLock => panic!("{}", e),
353 UnknownObjectStore(_) => FastlyStatus::Inval,
354 }
355 }
356}
357
358#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, thiserror::Error)]
359pub enum KvStoreError {
360 #[error("The error was not set")]
361 Uninitialized,
362 #[error("KV store cannot or will not process the request due to something that is perceived to be a client error")]
363 BadRequest,
364 #[error("KV store cannot fulfill the request, as definied by the client's prerequisites (ie. if-generation-match)")]
365 PreconditionFailed,
366 #[error("The size limit for a KV store key was exceeded")]
367 PayloadTooLarge,
368 #[error("The system encountered an unexpected internal error")]
369 InternalError,
370 #[error("Too many requests have been made to the KV store")]
371 TooManyRequests,
372}
373
374impl From<&KvError> for Result<Option<()>, KvStoreError> {
375 fn from(e: &KvError) -> Self {
376 Err(match e {
377 KvError::Ok => return Ok(Some(())),
378 KvError::NotFound => return Ok(None),
379 KvError::Uninitialized => KvStoreError::Uninitialized,
380 KvError::BadRequest => KvStoreError::BadRequest,
381 KvError::PreconditionFailed => KvStoreError::PreconditionFailed,
382 KvError::PayloadTooLarge => KvStoreError::PayloadTooLarge,
383 KvError::InternalError => KvStoreError::InternalError,
384 KvError::TooManyRequests => KvStoreError::TooManyRequests,
385 })
386 }
387}
388
389impl From<&KvStoreError> for KvError {
390 fn from(e: &KvStoreError) -> Self {
391 match e {
392 KvStoreError::Uninitialized => KvError::Uninitialized,
393 KvStoreError::BadRequest => KvError::BadRequest,
394 KvStoreError::PreconditionFailed => KvError::PreconditionFailed,
395 KvStoreError::PayloadTooLarge => KvError::PayloadTooLarge,
396 KvStoreError::InternalError => KvError::InternalError,
397 KvStoreError::TooManyRequests => KvError::TooManyRequests,
398 }
399 }
400}
401
402impl From<&KvStoreError> for FastlyStatus {
403 fn from(e: &KvStoreError) -> Self {
404 match e {
405 KvStoreError::Uninitialized => panic!("{}", e),
406 KvStoreError::BadRequest => FastlyStatus::Inval,
407 KvStoreError::PreconditionFailed => FastlyStatus::Inval,
408 KvStoreError::PayloadTooLarge => FastlyStatus::Inval,
409 KvStoreError::InternalError => FastlyStatus::Inval,
410 KvStoreError::TooManyRequests => FastlyStatus::Inval,
411 }
412 }
413}
414
415fn is_valid_key(key: &str) -> Result<(), KeyValidationError> {
425 let len = key.as_bytes().len();
426 if len < 1 {
427 return Err(KeyValidationError::EmptyKey);
428 } else if len > 1024 {
429 return Err(KeyValidationError::Over1024Bytes);
430 }
431
432 if key.starts_with(".well-known/acme-challenge") {
433 return Err(KeyValidationError::StartsWithWellKnown);
434 }
435
436 if key.eq("..") || key.contains("../") || key.ends_with("/..") {
437 return Err(KeyValidationError::ContainsDotDot);
438 } else if key.eq(".") || key.contains("./") || key.ends_with("/.") {
439 return Err(KeyValidationError::ContainsDot);
440 } else if key.contains('\r') {
441 return Err(KeyValidationError::Contains("\r".to_owned()));
442 } else if key.contains('\n') {
443 return Err(KeyValidationError::Contains("\n".to_owned()));
444 } else if key.contains('#') {
445 return Err(KeyValidationError::Contains("#".to_owned()));
446 } else if key.contains(';') {
447 return Err(KeyValidationError::Contains(";".to_owned()));
448 } else if key.contains('?') {
449 return Err(KeyValidationError::Contains("?".to_owned()));
450 } else if key.contains('^') {
451 return Err(KeyValidationError::Contains("^".to_owned()));
452 } else if key.contains('|') {
453 return Err(KeyValidationError::Contains("|".to_owned()));
454 }
455
456 if key.len() == 1 {
457 let k = key.chars().next().unwrap();
458 match k {
459 '\u{0}'..='\u{20}' => {
460 return Err(KeyValidationError::Contains(k.escape_unicode().to_string()));
461 }
462 '\u{FFFE}'..='\u{FFFF}' => {
463 return Err(KeyValidationError::Contains(k.escape_unicode().to_string()));
464 }
465 _ => {}
466 }
467 }
468
469 Ok(())
470}
471
472#[derive(Debug, thiserror::Error)]
473pub enum KeyValidationError {
474 #[error("Keys for objects cannot be empty")]
475 EmptyKey,
476 #[error("Keys for objects cannot be over 1024 bytes in size")]
477 Over1024Bytes,
478 #[error("Keys for objects cannot start with `.well-known/acme-challenge`")]
479 StartsWithWellKnown,
480 #[error("Keys for objects cannot be named `.`")]
481 ContainsDot,
482 #[error("Keys for objects cannot be named `..`")]
483 ContainsDotDot,
484 #[error("Keys for objects cannot contain a `{0}`")]
485 Contains(String),
486}
487
488#[cfg(test)]
489mod tests {
490 use super::*;
491
492 const STORE_NAME: &'static str = "test_store";
493
494 #[test]
495 fn test_kv_store_exists() {
496 let stores = ObjectStores::default();
497 stores
498 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
499 .unwrap();
500
501 let res = stores.store_exists(STORE_NAME);
502 match res {
503 Ok(true) => {}
504 Ok(false) => panic!("should have been Ok(true)"),
505 Err(e) => panic!("should not have been Err({:?})", e),
506 }
507 }
508
509 #[test]
510 fn test_kv_store_basics() {
511 let stores = ObjectStores::default();
512 stores
513 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
514 .unwrap();
515
516 let key = "insert_key".to_string();
517 let val1 = "val1".to_string();
518
519 let res = stores.insert(
521 ObjectStoreKey(STORE_NAME.to_string()),
522 ObjectKey(key.clone()),
523 val1.clone().into(),
524 KvInsertMode::Overwrite,
525 None,
526 None,
527 None,
528 );
529 match res {
530 Err(e) => panic!("should not have been Err({:?})", e),
531 _ => {}
532 }
533
534 let res = stores.lookup(
536 ObjectStoreKey(STORE_NAME.to_string()),
537 ObjectKey(key.clone()),
538 );
539 match res {
540 Ok(Some(ov)) => {
541 assert_eq!(ov.body, val1.as_bytes().to_vec())
542 }
543 Ok(None) => panic!("should have been Ok(Some(_))"),
544 Err(_) => panic!("should have been Ok(_)"),
545 }
546
547 let limit = 1000;
549 let res = stores.list(ObjectStoreKey(STORE_NAME.to_string()), None, None, limit);
550 match res {
551 Ok(ov) => {
552 let val = format!(r#"{{"data":["{key}"],"meta":{{"limit":{limit}}}}}"#);
553 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
554 }
555 Err(e) => panic!("should not have been Err({:?})", e),
556 }
557
558 let res = stores.delete(
560 ObjectStoreKey(STORE_NAME.to_string()),
561 ObjectKey(key.clone()),
562 );
563 match res {
564 Ok(_) => {}
565 Err(e) => panic!("should not have been Err({:?})", e),
566 }
567 }
568
569 #[test]
570 fn test_kv_store_item_404s() {
571 let stores = ObjectStores::default();
572 stores
573 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
574 .unwrap();
575
576 let res = stores.lookup(
577 ObjectStoreKey(STORE_NAME.to_string()),
578 ObjectKey("bad_key".to_string()),
579 );
580 match res {
581 Ok(Some(_)) => panic!("should have been Ok(None)"),
582 Ok(None) => {}
583 Err(e) => panic!("should not have been Err({:?})", e),
584 }
585
586 let res = stores.delete(
587 ObjectStoreKey(STORE_NAME.to_string()),
588 ObjectKey("bad_key".to_string()),
589 );
590 match res {
591 Ok(true) => panic!("should have been Ok(false)"),
592 Ok(false) => {}
593 Err(e) => panic!("should not have been Err({:?})", e),
594 }
595 }
596
597 #[test]
598 fn test_kv_store_item_insert_modes() {
599 let stores = ObjectStores::default();
600 stores
601 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
602 .unwrap();
603
604 let key = "insert_key".to_string();
605 let val1 = "val1".to_string();
606 let val2 = "val2".to_string();
607 let val3 = "val3".to_string();
608
609 let res = stores.insert(
610 ObjectStoreKey(STORE_NAME.to_string()),
611 ObjectKey(key.clone()),
612 val1.clone().into(),
613 KvInsertMode::Add,
614 None,
615 None,
616 None,
617 );
618 assert!(res.is_ok());
619 let res = stores.insert(
621 ObjectStoreKey(STORE_NAME.to_string()),
622 ObjectKey(key.clone()),
623 val1.clone().into(),
624 KvInsertMode::Add,
625 None,
626 None,
627 None,
628 );
629 match res {
630 Ok(_) => panic!("should not have been OK"),
631 Err(e) => assert_eq!(e, KvStoreError::PreconditionFailed),
632 }
633 let res = stores.insert(
635 ObjectStoreKey(STORE_NAME.to_string()),
636 ObjectKey(key.clone()),
637 val2.clone().into(),
638 KvInsertMode::Prepend,
639 None,
640 None,
641 None,
642 );
643 match res {
644 Err(e) => panic!("should not have been Err({:?})", e),
645 _ => {}
646 }
647 let res = stores.insert(
649 ObjectStoreKey(STORE_NAME.to_string()),
650 ObjectKey(key.clone()),
651 val3.clone().into(),
652 KvInsertMode::Append,
653 None,
654 None,
655 None,
656 );
657 match res {
658 Err(e) => panic!("should not have been Err({:?})", e),
659 _ => {}
660 }
661 let res = stores.lookup(
662 ObjectStoreKey(STORE_NAME.to_string()),
663 ObjectKey(key.clone()),
664 );
665 match res {
666 Ok(Some(ov)) => {
667 let val = format!("{val2}{val1}{val3}");
668 assert_eq!(ov.body, val.as_bytes().to_vec())
669 }
670 Ok(None) => panic!("should have been Ok(Some((_))"),
671 Err(e) => panic!("should not have been Err({:?})", e),
672 }
673
674 let res = stores.insert(
676 ObjectStoreKey(STORE_NAME.to_string()),
677 ObjectKey(key.clone()),
678 val3.clone().into(),
679 KvInsertMode::Overwrite,
680 None,
681 Some(val2.clone()),
682 None,
683 );
684 match res {
685 Err(e) => panic!("should not have been Err({:?})", e),
686 _ => {}
687 }
688
689 let res = stores.lookup(
691 ObjectStoreKey(STORE_NAME.to_string()),
692 ObjectKey(key.clone()),
693 );
694 match res {
695 Ok(Some(ov)) => {
696 assert_eq!(ov.body, val3.as_bytes().to_vec());
697 assert_eq!(ov.metadata, val2);
698 }
699 Ok(None) => panic!("should have been Ok(Some(_))"),
700 Err(e) => panic!("should not have been Err({:?})", e),
701 }
702 }
703
704 #[test]
705 fn test_kv_store_item_insert_generation() {
706 let stores = ObjectStores::default();
707 stores
708 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
709 .unwrap();
710
711 let key = "insert_key".to_string();
712 let val1 = "val1".to_string();
713
714 let res = stores.insert(
716 ObjectStoreKey(STORE_NAME.to_string()),
717 ObjectKey(key.clone()),
718 val1.clone().into(),
719 KvInsertMode::Overwrite,
720 None,
721 None,
722 None,
723 );
724 match res {
725 Err(e) => panic!("should not have been Err({:?})", e),
726 _ => {}
727 }
728
729 let generation;
731 let res = stores.lookup(
732 ObjectStoreKey(STORE_NAME.to_string()),
733 ObjectKey(key.clone()),
734 );
735 match res {
736 Ok(Some(ov)) => {
737 assert_eq!(ov.body, val1.as_bytes().to_vec());
738 generation = ov.generation;
739 }
740 Ok(None) => panic!("should have been Ok(Some(_))"),
741 Err(e) => panic!("should not have been Err({:?})", e),
742 }
743
744 let res = stores.insert(
746 ObjectStoreKey(STORE_NAME.to_string()),
747 ObjectKey(key.clone()),
748 val1.clone().into(),
749 KvInsertMode::Overwrite,
750 Some(1337),
751 None,
752 None,
753 );
754 match res {
755 Err(KvStoreError::PreconditionFailed) => {}
756 _ => panic!("should have been Err(KvStoreError::PreconditionFailed)"),
757 }
758
759 let res = stores.insert(
761 ObjectStoreKey(STORE_NAME.to_string()),
762 ObjectKey(key.clone()),
763 val1.clone().into(),
764 KvInsertMode::Overwrite,
765 Some(generation),
766 None,
767 None,
768 );
769 match res {
770 Ok(_) => {}
771 Err(e) => panic!("should not have been Err({:?})", e),
772 }
773
774 let res = stores.lookup(
776 ObjectStoreKey(STORE_NAME.to_string()),
777 ObjectKey(key.clone()),
778 );
779 match res {
780 Ok(Some(ov)) => {
781 assert_eq!(ov.body, val1.as_bytes().to_vec());
782 }
783 Ok(None) => panic!("should have been Ok(Some(_))"),
784 Err(e) => panic!("should not have been Err({:?})", e),
785 }
786 }
787
788 #[test]
789 fn test_kv_store_item_list_advanced() {
790 let stores = ObjectStores::default();
791 stores
792 .insert_empty_store(ObjectStoreKey(STORE_NAME.to_string()))
793 .unwrap();
794
795 let key = "insert_key".to_string();
796 let prefix = "key".to_string();
797 let key1 = format!("{prefix}1").to_string();
798 let key2 = format!("{prefix}2").to_string();
799 let key3 = format!("{prefix}3").to_string();
800 let val1 = "val1".to_string();
801 let val2 = "val2".to_string();
802 let val3 = "val3".to_string();
803
804 let res = stores.insert(
806 ObjectStoreKey(STORE_NAME.to_string()),
807 ObjectKey(key.clone()),
808 val1.clone().into(),
809 KvInsertMode::Overwrite,
810 None,
811 None,
812 None,
813 );
814 match res {
815 Err(e) => panic!("should not have been Err({:?})", e),
816 _ => {}
817 }
818
819 let res = stores.insert(
821 ObjectStoreKey(STORE_NAME.to_string()),
822 ObjectKey(key1.clone()),
823 val1.clone().into(),
824 KvInsertMode::Overwrite,
825 None,
826 None,
827 None,
828 );
829 match res {
830 Err(e) => panic!("should not have been Err({:?})", e),
831 _ => {}
832 }
833 let res = stores.insert(
835 ObjectStoreKey(STORE_NAME.to_string()),
836 ObjectKey(key2.clone()),
837 val2.clone().into(),
838 KvInsertMode::Overwrite,
839 None,
840 None,
841 None,
842 );
843 match res {
844 Err(e) => panic!("should not have been Err({:?})", e),
845 _ => {}
846 }
847 let res = stores.insert(
849 ObjectStoreKey(STORE_NAME.to_string()),
850 ObjectKey(key3.clone()),
851 val3.clone().into(),
852 KvInsertMode::Overwrite,
853 None,
854 None,
855 None,
856 );
857 match res {
858 Err(e) => panic!("should not have been Err({:?})", e),
859 _ => {}
860 }
861
862 let limit = 1000;
864 let res = stores.list(ObjectStoreKey(STORE_NAME.to_string()), None, None, limit);
865 match res {
866 Ok(ov) => {
867 let val = format!(
868 r#"{{"data":["{key}","{key1}","{key2}","{key3}"],"meta":{{"limit":{limit}}}}}"#
869 );
870 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
871 }
872 Err(e) => panic!("should not have been Err({:?})", e),
873 }
874
875 let limit = 1000;
877 let res = stores.list(
878 ObjectStoreKey(STORE_NAME.to_string()),
879 None,
880 Some(prefix.clone()),
881 limit,
882 );
883 match res {
884 Ok(ov) => {
885 let val = format!(
886 r#"{{"data":["{key1}","{key2}","{key3}"],"meta":{{"limit":{limit},"prefix":"{prefix}"}}}}"#
887 );
888 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
889 }
890 Err(e) => panic!("should not have been Err({:?})", e),
891 }
892
893 let limit = 1;
895 let res = stores.list(
896 ObjectStoreKey(STORE_NAME.to_string()),
897 None,
898 Some(prefix.clone()),
899 limit,
900 );
901 match res {
902 Ok(ov) => {
903 let next_cursor = BASE64_STANDARD.encode(key1.clone());
904 let val = format!(
905 r#"{{"data":["{key1}"],"meta":{{"limit":{limit},"prefix":"{prefix}","next_cursor":"{next_cursor}"}}}}"#
906 );
907 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
908 }
909 Err(e) => panic!("should not have been Err({:?})", e),
910 }
911
912 let limit = 1;
914 let last_cursor = BASE64_STANDARD.encode(key1.clone());
915 let res = stores.list(
916 ObjectStoreKey(STORE_NAME.to_string()),
917 Some(last_cursor),
918 Some(prefix.clone()),
919 limit,
920 );
921 match res {
922 Ok(ov) => {
923 let next_cursor = BASE64_STANDARD.encode(key2.clone());
924 let val = format!(
925 r#"{{"data":["{key2}"],"meta":{{"limit":{limit},"prefix":"{prefix}","next_cursor":"{next_cursor}"}}}}"#
926 );
927 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
928 }
929 Err(e) => panic!("should not have been Err({:?})", e),
930 }
931
932 let limit = 1;
934 let last_cursor = BASE64_STANDARD.encode(key2.clone());
935 let res = stores.list(
936 ObjectStoreKey(STORE_NAME.to_string()),
937 Some(last_cursor),
938 Some(prefix.clone()),
939 limit,
940 );
941 match res {
942 Ok(ov) => {
943 let val = format!(
944 r#"{{"data":["{key3}"],"meta":{{"limit":{limit},"prefix":"{prefix}"}}}}"#
945 );
946 assert_eq!(std::str::from_utf8(&ov).unwrap(), val)
947 }
948 Err(e) => panic!("should not have been Err({:?})", e),
949 }
950 }
951}