trino_rust_client/spooling/
segment.rs1use serde::Deserialize;
2use serde::Serialize;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct DataAttributes {
9 #[serde(flatten)]
10 attributes: HashMap<String, serde_json::Value>,
11}
12
13impl DataAttributes {
15 pub fn row_offset(&self) -> Option<u64> {
17 self.attributes.get("rowOffset")?.as_u64()
18 }
19
20 pub fn rows_count(&self) -> Option<u64> {
22 self.attributes.get("rowsCount")?.as_u64()
23 }
24
25 pub fn segment_size(&self) -> Option<u64> {
27 self.attributes.get("segmentSize")?.as_u64()
28 }
29}
30
31#[derive(Debug, PartialEq, Deserialize, Serialize)]
33#[serde(rename_all = "camelCase", untagged)]
34pub enum Segment {
35 Inlined {
37 #[serde(rename = "type")]
38 segment_type: String,
39 data: String,
40 metadata: DataAttributes,
41 },
42 Spooled {
44 #[serde(rename = "type")]
45 segment_type: String,
46 uri: String,
47 #[serde(rename = "ackUri")]
48 #[serde(skip_serializing_if = "Option::is_none")]
49 ack_uri: Option<String>,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 headers: Option<HashMap<String, Vec<String>>>,
52 metadata: DataAttributes,
53 },
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_deserialize_inlined_segment() {
62 let json = r#"{
63 "type": "inline",
64 "data": "SGVsbG8gV29ybGQ=",
65 "metadata": {
66 "rowOffset": 0,
67 "rowsCount": 1,
68 "segmentSize": 1024
69 }
70 }"#;
71 let segment: Segment = serde_json::from_str(json).unwrap();
72 match segment {
73 Segment::Inlined {
74 segment_type,
75 data,
76 metadata,
77 } => {
78 assert_eq!(segment_type, "inline");
79 assert_eq!(data, "SGVsbG8gV29ybGQ=");
80 assert_eq!(metadata.row_offset(), Some(0));
81 assert_eq!(metadata.rows_count(), Some(1));
82 assert_eq!(metadata.segment_size(), Some(1024));
83 }
84 _ => panic!("Expected Inlined segment"),
85 }
86 }
87
88 #[test]
89 fn test_deserialize_spooled_segment_minimal() {
90 let json = r#"{
91 "type": "spooled",
92 "uri": "http://minio:9000/bucket/segment.json?signature=abc123",
93 "metadata": {
94 "rowOffset": 0,
95 "rowsCount": 1000,
96 "segmentSize": 1048576
97 }
98 }"#;
99 let segment: Segment = serde_json::from_str(json).unwrap();
100 match segment {
101 Segment::Spooled {
102 segment_type,
103 uri,
104 ack_uri,
105 headers,
106 metadata,
107 } => {
108 assert_eq!(segment_type, "spooled");
109 assert_eq!(
110 uri,
111 "http://minio:9000/bucket/segment.json?signature=abc123"
112 );
113 assert_eq!(ack_uri, None);
114 assert_eq!(headers, None);
115 assert_eq!(metadata.row_offset(), Some(0));
116 assert_eq!(metadata.rows_count(), Some(1000));
117 assert_eq!(metadata.segment_size(), Some(1048576));
118 }
119 _ => panic!("Expected Spooled segment"),
120 }
121 }
122
123 #[test]
124 fn test_deserialize_spooled_segment_with_ack() {
125 let json = r#"{
126 "type": "spooled",
127 "uri": "http://minio:9000/bucket/segment.json",
128 "ackUri": "http://minio:9000/bucket/segment.ack",
129 "headers": {
130 "X-Custom": ["value1"]
131 },
132 "metadata": {
133 "rowOffset": 0,
134 "rowsCount": 100
135 }
136 }"#;
137 let segment: Segment = serde_json::from_str(json).unwrap();
138 match segment {
139 Segment::Spooled {
140 segment_type,
141 uri,
142 ack_uri,
143 headers,
144 metadata,
145 } => {
146 assert_eq!(segment_type, "spooled");
147 assert_eq!(uri, "http://minio:9000/bucket/segment.json");
148 assert_eq!(
149 ack_uri,
150 Some("http://minio:9000/bucket/segment.ack".to_string())
151 );
152 assert!(headers.is_some());
153 assert_eq!(metadata.row_offset(), Some(0));
154 assert_eq!(metadata.rows_count(), Some(100));
155 }
156 _ => panic!("Expected Spooled segment"),
157 }
158 }
159
160 #[test]
161 fn test_deserialize_inlined_segment_minimal() {
162 let json = r#"{
163 "type": "inline",
164 "data": "YWJjZGVmZw==",
165 "metadata": {}
166 }"#;
167 let segment: Segment = serde_json::from_str(json).unwrap();
168 match segment {
169 Segment::Inlined {
170 segment_type,
171 data,
172 metadata,
173 } => {
174 assert_eq!(segment_type, "inline");
175 assert_eq!(data, "YWJjZGVmZw==");
176 assert_eq!(metadata.row_offset(), None);
177 assert_eq!(metadata.rows_count(), None);
178 assert_eq!(metadata.segment_size(), None);
179 }
180 _ => panic!("Expected Inlined segment"),
181 }
182 }
183
184 #[test]
185 fn test_data_attributes_row_offset() {
186 let json = r#"{
187 "rowOffset": 42
188 }"#;
189 let data_attributes: DataAttributes = serde_json::from_str(json).unwrap();
190 assert_eq!(data_attributes.row_offset(), Some(42));
191 assert_eq!(data_attributes.rows_count(), None);
192 assert_eq!(data_attributes.segment_size(), None);
193 }
194
195 #[test]
196 fn test_data_attributes_rows_count() {
197 let json = r#"{
198 "rowsCount": 100
199 }"#;
200 let data_attributes: DataAttributes = serde_json::from_str(json).unwrap();
201 assert_eq!(data_attributes.row_offset(), None);
202 assert_eq!(data_attributes.rows_count(), Some(100));
203 assert_eq!(data_attributes.segment_size(), None);
204 }
205
206 #[test]
207 fn test_data_attributes_segment_size() {
208 let json = r#"{
209 "segmentSize": 4096
210 }"#;
211 let data_attributes: DataAttributes = serde_json::from_str(json).unwrap();
212 assert_eq!(data_attributes.row_offset(), None);
213 assert_eq!(data_attributes.rows_count(), None);
214 assert_eq!(data_attributes.segment_size(), Some(4096));
215 }
216
217 #[test]
218 fn test_data_attributes_all_fields() {
219 let json = r#"{
220 "rowOffset": 0,
221 "rowsCount": 10,
222 "segmentSize": 512
223 }"#;
224 let data_attributes: DataAttributes = serde_json::from_str(json).unwrap();
225 assert_eq!(data_attributes.row_offset(), Some(0));
226 assert_eq!(data_attributes.rows_count(), Some(10));
227 assert_eq!(data_attributes.segment_size(), Some(512));
228 }
229
230 #[test]
231 fn test_spooled_segment_with_multiple_header_values() {
232 let json = r#"{
233 "type": "spooled",
234 "uri": "http://storage/segment.json",
235 "ackUri": "http://storage/segment.ack",
236 "headers": {
237 "Authorization": ["Bearer token123"],
238 "X-Custom": ["value1", "value2"]
239 },
240 "metadata": {
241 "rowOffset": 100,
242 "rowsCount": 50
243 }
244 }"#;
245 let segment: Segment = serde_json::from_str(json).unwrap();
246
247 match segment {
248 Segment::Spooled {
249 uri,
250 ack_uri,
251 headers,
252 metadata,
253 ..
254 } => {
255 assert_eq!(uri, "http://storage/segment.json");
256 assert_eq!(ack_uri, Some("http://storage/segment.ack".to_string()));
257 assert!(headers.is_some());
258 let headers_map = headers.unwrap();
259 assert_eq!(
260 headers_map.get("Authorization"),
261 Some(&vec!["Bearer token123".to_string()])
262 );
263 assert_eq!(
264 headers_map.get("X-Custom"),
265 Some(&vec!["value1".to_string(), "value2".to_string()])
266 );
267 assert_eq!(metadata.row_offset(), Some(100));
268 assert_eq!(metadata.rows_count(), Some(50));
269 }
270 _ => panic!("Expected Spooled segment"),
271 }
272 }
273}