1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub struct StrongRef {
11 pub uri: String,
13 pub cid: String,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22pub struct BlobRef {
23 #[serde(rename = "$type")]
25 pub blob_type: String,
26 #[serde(rename = "ref")]
28 pub reference: BlobLink,
29 #[serde(rename = "mimeType")]
31 pub mime_type: String,
32 pub size: u64,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct BlobLink {
39 #[serde(rename = "$link")]
41 pub link: String,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct Page<T> {
50 pub records: Vec<T>,
52 pub cursor: Option<String>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct Record<T> {
59 pub uri: String,
61 pub cid: String,
63 pub value: T,
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn strong_ref_serde_round_trip() {
73 let strong = StrongRef {
74 uri: "at://did:plc:abc123/app.bsky.feed.post/3k2la".into(),
75 cid: "bafyreib2rxk3rybkba".into(),
76 };
77 let json = serde_json::to_string(&strong).unwrap();
78 let decoded: StrongRef = serde_json::from_str(&json).unwrap();
79 assert_eq!(strong, decoded);
80 }
81
82 #[test]
83 fn blob_ref_serde_round_trip() {
84 let blob = BlobRef {
85 blob_type: "blob".into(),
86 reference: BlobLink {
87 link: "bafyreib2rxk3rybkba".into(),
88 },
89 mime_type: "image/png".into(),
90 size: 12345,
91 };
92 let json = serde_json::to_string(&blob).unwrap();
93 let decoded: BlobRef = serde_json::from_str(&json).unwrap();
94 assert_eq!(blob, decoded);
95 }
96
97 #[test]
98 fn blob_ref_json_field_names() {
99 let blob = BlobRef {
100 blob_type: "blob".into(),
101 reference: BlobLink {
102 link: "bafyreib2rxk3rybkba".into(),
103 },
104 mime_type: "image/jpeg".into(),
105 size: 999,
106 };
107 let val: serde_json::Value = serde_json::to_value(&blob).unwrap();
108 assert!(val.get("$type").is_some());
109 assert!(val.get("ref").is_some());
110 assert!(val.get("mimeType").is_some());
111 let ref_obj = val.get("ref").unwrap();
112 assert!(ref_obj.get("$link").is_some());
113 }
114
115 #[test]
116 fn page_serde_round_trip() {
117 let page: Page<StrongRef> = Page {
118 records: vec![StrongRef {
119 uri: "at://did:plc:abc/col.name/rkey".into(),
120 cid: "bafyxyz".into(),
121 }],
122 cursor: Some("next_cursor".into()),
123 };
124 let json = serde_json::to_string(&page).unwrap();
125 let decoded: Page<StrongRef> = serde_json::from_str(&json).unwrap();
126 assert_eq!(decoded.records.len(), 1);
127 assert_eq!(decoded.cursor.as_deref(), Some("next_cursor"));
128 }
129
130 #[test]
131 fn page_last_page_has_no_cursor() {
132 let page: Page<StrongRef> = Page {
133 records: vec![],
134 cursor: None,
135 };
136 let json = serde_json::to_string(&page).unwrap();
137 let decoded: Page<StrongRef> = serde_json::from_str(&json).unwrap();
138 assert!(decoded.cursor.is_none());
139 }
140
141 #[test]
142 fn record_serde_round_trip() {
143 let record: Record<serde_json::Value> = Record {
144 uri: "at://did:plc:abc/col.name/rkey".into(),
145 cid: "bafyxyz".into(),
146 value: serde_json::json!({"text": "hello"}),
147 };
148 let json = serde_json::to_string(&record).unwrap();
149 let decoded: Record<serde_json::Value> = serde_json::from_str(&json).unwrap();
150 assert_eq!(decoded.uri, "at://did:plc:abc/col.name/rkey");
151 assert_eq!(decoded.value["text"], "hello");
152 }
153}