paginator_utils/
cursor.rs1use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
5pub struct Cursor {
6 pub field: String,
7 pub value: CursorValue,
8 pub direction: CursorDirection,
9}
10
11#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
12#[serde(rename_all = "lowercase")]
13pub enum CursorDirection {
14 After,
15 Before,
16}
17
18#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
19#[serde(untagged)]
20pub enum CursorValue {
21 String(String),
22 Int(i64),
23 Float(f64),
24 Uuid(String),
26}
27
28impl Cursor {
29 pub fn new(field: String, value: CursorValue, direction: CursorDirection) -> Self {
30 Self {
31 field,
32 value,
33 direction,
34 }
35 }
36
37 pub fn encode(&self) -> Result<String, String> {
38 let json = serde_json::to_string(self).map_err(|e| e.to_string())?;
39 Ok(BASE64.encode(json.as_bytes()))
40 }
41
42 pub fn decode(encoded: &str) -> Result<Self, String> {
43 let decoded = BASE64.decode(encoded).map_err(|e| e.to_string())?;
44 let json = String::from_utf8(decoded).map_err(|e| e.to_string())?;
45 serde_json::from_str(&json).map_err(|e| e.to_string())
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn test_cursor_encode_decode_string() {
55 let cursor = Cursor::new(
56 "id".to_string(),
57 CursorValue::String("abc123".to_string()),
58 CursorDirection::After,
59 );
60 let encoded = cursor.encode().unwrap();
61 let decoded = Cursor::decode(&encoded).unwrap();
62 assert_eq!(cursor, decoded);
63 }
64
65 #[test]
66 fn test_cursor_encode_decode_int() {
67 let cursor = Cursor::new(
68 "id".to_string(),
69 CursorValue::Int(12345),
70 CursorDirection::Before,
71 );
72 let encoded = cursor.encode().unwrap();
73 let decoded = Cursor::decode(&encoded).unwrap();
74 assert_eq!(cursor, decoded);
75 }
76
77 #[test]
78 fn test_cursor_encode_decode_float() {
79 let cursor = Cursor::new(
80 "timestamp".to_string(),
81 CursorValue::Float(1234567890.123),
82 CursorDirection::After,
83 );
84 let encoded = cursor.encode().unwrap();
85 let decoded = Cursor::decode(&encoded).unwrap();
86 assert_eq!(cursor, decoded);
87 }
88}