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}
25
26impl Cursor {
27 pub fn new(field: String, value: CursorValue, direction: CursorDirection) -> Self {
28 Self {
29 field,
30 value,
31 direction,
32 }
33 }
34
35 pub fn encode(&self) -> Result<String, String> {
36 let json = serde_json::to_string(self).map_err(|e| e.to_string())?;
37 Ok(BASE64.encode(json.as_bytes()))
38 }
39
40 pub fn decode(encoded: &str) -> Result<Self, String> {
41 let decoded = BASE64.decode(encoded).map_err(|e| e.to_string())?;
42 let json = String::from_utf8(decoded).map_err(|e| e.to_string())?;
43 serde_json::from_str(&json).map_err(|e| e.to_string())
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn test_cursor_encode_decode_string() {
53 let cursor = Cursor::new(
54 "id".to_string(),
55 CursorValue::String("abc123".to_string()),
56 CursorDirection::After,
57 );
58 let encoded = cursor.encode().unwrap();
59 let decoded = Cursor::decode(&encoded).unwrap();
60 assert_eq!(cursor, decoded);
61 }
62
63 #[test]
64 fn test_cursor_encode_decode_int() {
65 let cursor = Cursor::new(
66 "id".to_string(),
67 CursorValue::Int(12345),
68 CursorDirection::Before,
69 );
70 let encoded = cursor.encode().unwrap();
71 let decoded = Cursor::decode(&encoded).unwrap();
72 assert_eq!(cursor, decoded);
73 }
74
75 #[test]
76 fn test_cursor_encode_decode_float() {
77 let cursor = Cursor::new(
78 "timestamp".to_string(),
79 CursorValue::Float(1234567890.123),
80 CursorDirection::After,
81 );
82 let encoded = cursor.encode().unwrap();
83 let decoded = Cursor::decode(&encoded).unwrap();
84 assert_eq!(cursor, decoded);
85 }
86}