open_lark/service/cloud_docs/sheets/v2/data_operation/
prepend_data.rs

1use serde::Serialize;
2use serde_json::Value;
3
4use crate::{
5    core::{
6        api_req::ApiRequest, api_resp::BaseResponse, constants::AccessTokenType,
7        endpoints::cloud_docs::*, req_option::RequestOption, SDKResult,
8    },
9    service::cloud_docs::sheets::v2::{
10        data_operation::{UpdateSheetDataResponse, ValueRangeRequest},
11        SpreadsheetSheetService,
12    },
13};
14
15/// 插入数据请求
16#[derive(Serialize, Debug, Default)]
17pub struct PrependDataRequest {
18    #[serde(skip)]
19    api_request: ApiRequest,
20    #[serde(skip)]
21    spreadsheet_token: String,
22    /// 值与范围
23    #[serde(rename = "valueRange")]
24    value_range: ValueRangeRequest,
25}
26
27impl PrependDataRequest {
28    pub fn builder() -> PrependDataRequestBuilder {
29        PrependDataRequestBuilder::default()
30    }
31}
32
33#[derive(Default)]
34pub struct PrependDataRequestBuilder {
35    request: PrependDataRequest,
36}
37
38impl PrependDataRequestBuilder {
39    pub fn spreadsheet_token(mut self, spreadsheet_token: impl ToString) -> Self {
40        self.request.spreadsheet_token = spreadsheet_token.to_string();
41        self
42    }
43
44    /// 插入范围,包含 sheetId 与单元格范围两部分,目前支持四种索引方式,详见
45    /// 在线表格开发指南,range所表示的范围需要大于等于values占用的范围。
46    pub fn range(mut self, range: impl ToString) -> Self {
47        self.request.value_range.range = range.to_string();
48        self
49    }
50
51    /// 需要写入的值,如要写入公式、超链接、email、@人等,可详看附录sheet 支持写入数据类型
52    pub fn values(mut self, values: Value) -> Self {
53        self.request.value_range.values = values;
54        self
55    }
56
57    pub fn build(mut self) -> PrependDataRequest {
58        self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
59        self.request
60    }
61}
62
63/// 插入数据响应体
64pub type PrependDataResponse = UpdateSheetDataResponse;
65
66impl SpreadsheetSheetService {
67    /// 插入数据
68    pub async fn prepend_data(
69        &self,
70        request: PrependDataRequest,
71        option: Option<RequestOption>,
72    ) -> SDKResult<BaseResponse<PrependDataResponse>> {
73        let mut api_req = request.api_request;
74        api_req.api_path =
75            SHEETS_V2_SPREADSHEET_VALUES_PREPEND.replace("{}", &request.spreadsheet_token);
76        api_req.http_method = reqwest::Method::POST;
77        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::App];
78
79        let api_resp =
80            crate::core::http::Transport::request(api_req, &self.config_arc, option).await?;
81
82        Ok(api_resp)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::core::{config::Config, constants::AppType};
90    use serde_json::{json, Value};
91
92    fn create_test_config() -> Config {
93        Config::builder()
94            .app_id("test_app_id")
95            .app_secret("test_app_secret")
96            .build()
97    }
98
99    fn create_test_service() -> SpreadsheetSheetService {
100        SpreadsheetSheetService::new(create_test_config())
101    }
102
103    #[test]
104    fn test_prepend_data_request_builder_creation() {
105        let builder = PrependDataRequest::builder();
106        let request = builder.build();
107
108        assert_eq!(request.spreadsheet_token, "");
109        assert_eq!(request.value_range.range, "");
110        assert_eq!(request.value_range.values, Value::Null);
111    }
112
113    #[test]
114    fn test_prepend_data_request_builder_with_spreadsheet_token() {
115        let request = PrependDataRequest::builder()
116            .spreadsheet_token("prepend_token_123")
117            .build();
118
119        assert_eq!(request.spreadsheet_token, "prepend_token_123");
120    }
121
122    #[test]
123    fn test_prepend_data_request_builder_with_range() {
124        let request = PrependDataRequest::builder().range("Sheet1!A1:D5").build();
125
126        assert_eq!(request.value_range.range, "Sheet1!A1:D5");
127    }
128
129    #[test]
130    fn test_prepend_data_request_builder_with_values() {
131        let test_values = json!([
132            ["Product", "Price", "Stock", "Category"],
133            ["Laptop", 999.99, 50, "Electronics"],
134            ["Mouse", 29.99, 200, "Accessories"]
135        ]);
136
137        let request = PrependDataRequest::builder()
138            .values(test_values.clone())
139            .build();
140
141        assert_eq!(request.value_range.values, test_values);
142    }
143
144    #[test]
145    fn test_prepend_data_request_builder_chaining() {
146        let test_values = json!([["Header1", "Header2"], ["Data1", "Data2"]]);
147
148        let request = PrependDataRequest::builder()
149            .spreadsheet_token("chain_token")
150            .range("Sheet2!B2:C3")
151            .values(test_values.clone())
152            .build();
153
154        assert_eq!(request.spreadsheet_token, "chain_token");
155        assert_eq!(request.value_range.range, "Sheet2!B2:C3");
156        assert_eq!(request.value_range.values, test_values);
157    }
158
159    #[test]
160    fn test_prepend_data_request_default() {
161        let request = PrependDataRequest::default();
162
163        assert_eq!(request.spreadsheet_token, "");
164        assert_eq!(request.value_range.range, "");
165        assert_eq!(request.value_range.values, Value::Null);
166    }
167
168    #[test]
169    fn test_prepend_data_request_builder_default() {
170        let builder = PrependDataRequestBuilder::default();
171        let request = builder.build();
172
173        assert_eq!(request.spreadsheet_token, "");
174        assert_eq!(request.value_range.range, "");
175        assert_eq!(request.value_range.values, Value::Null);
176    }
177
178    #[test]
179    fn test_prepend_data_request_serialization() {
180        let test_values = json!([["Col1", "Col2"], ["Val1", "Val2"]]);
181
182        let request = PrependDataRequest::builder()
183            .spreadsheet_token("serialize_token")
184            .range("Sheet1!A:B")
185            .values(test_values)
186            .build();
187
188        let serialized = serde_json::to_string(&request);
189        assert!(serialized.is_ok());
190
191        let json_str = serialized.unwrap();
192        assert!(json_str.contains("valueRange"));
193        assert!(!json_str.contains("spreadsheet_token")); // Should be skipped
194    }
195
196    #[test]
197    fn test_prepend_data_request_debug() {
198        let request = PrependDataRequest::builder()
199            .spreadsheet_token("debug_prepend_token")
200            .build();
201
202        let debug_str = format!("{:?}", request);
203        assert!(debug_str.contains("PrependDataRequest"));
204        assert!(debug_str.contains("debug_prepend_token"));
205    }
206
207    #[test]
208    fn test_prepend_data_request_with_empty_values() {
209        let request = PrependDataRequest::builder()
210            .spreadsheet_token("")
211            .range("")
212            .values(Value::Null)
213            .build();
214
215        assert_eq!(request.spreadsheet_token, "");
216        assert_eq!(request.value_range.range, "");
217        assert_eq!(request.value_range.values, Value::Null);
218    }
219
220    #[test]
221    fn test_prepend_data_request_with_special_characters() {
222        let request = PrependDataRequest::builder()
223            .spreadsheet_token("token_特殊字符_prepend_🎉")
224            .range("工作表!A1:Z999")
225            .build();
226
227        assert_eq!(request.spreadsheet_token, "token_特殊字符_prepend_🎉");
228        assert_eq!(request.value_range.range, "工作表!A1:Z999");
229    }
230
231    #[test]
232    fn test_prepend_data_request_with_unicode_data() {
233        let unicode_values = json!([
234            ["名称", "描述", "状态"],
235            ["测试项目", "这是一个测试项目", "活跃"],
236            ["实验数据", "包含中文和English混合", "完成"],
237            ["🚀项目", "包含emoji和特殊符号", "进行中"]
238        ]);
239
240        let request = PrependDataRequest::builder()
241            .values(unicode_values.clone())
242            .build();
243
244        assert_eq!(request.value_range.values, unicode_values);
245    }
246
247    #[test]
248    fn test_prepend_data_request_with_complex_json_structures() {
249        let complex_data = json!([
250            [
251                {"type": "formula", "value": "=SUM(A1:A10)"},
252                {"type": "link", "url": "https://example.com", "text": "Link"},
253                {"type": "mention", "user_id": "user123"}
254            ],
255            [
256                {"number": 42.5, "currency": "USD"},
257                {"date": "2023-12-25", "format": "yyyy-mm-dd"},
258                {"boolean": true, "confidence": 0.95}
259            ]
260        ]);
261
262        let request = PrependDataRequest::builder()
263            .values(complex_data.clone())
264            .build();
265
266        assert_eq!(request.value_range.values, complex_data);
267    }
268
269    #[test]
270    fn test_prepend_data_request_with_different_range_formats() {
271        let range_formats = vec![
272            "Sheet1!A1:B2",
273            "工作表名称!C:D",
274            "'Sheet with spaces'!E5:F10",
275            "Sheet2!A:A",
276            "数据表!1:5",
277            "Sheet!$A$1:$B$10",
278        ];
279
280        for range_format in range_formats {
281            let request = PrependDataRequest::builder().range(range_format).build();
282
283            assert_eq!(request.value_range.range, range_format);
284        }
285    }
286
287    #[test]
288    fn test_prepend_data_request_with_various_data_types() {
289        let mixed_types = vec![
290            json!("string_value"),
291            json!(123),
292            json!(45.67),
293            json!(true),
294            json!(false),
295            json!(null),
296            json!([1, 2, 3]),
297            json!({"key": "value", "nested": {"inner": "data"}}),
298        ];
299
300        for data_type in mixed_types {
301            let request = PrependDataRequest::builder()
302                .values(data_type.clone())
303                .build();
304
305            assert_eq!(request.value_range.values, data_type);
306        }
307    }
308
309    #[test]
310    fn test_prepend_data_request_api_body_serialization() {
311        let test_data = json!([["X", "Y"], ["1", "2"]]);
312
313        let request = PrependDataRequest::builder()
314            .spreadsheet_token("body_test")
315            .range("Sheet1!A:B")
316            .values(test_data)
317            .build();
318
319        // Verify body is populated
320        assert!(!request.api_request.body.is_empty());
321
322        // Verify body contains valid JSON
323        let body_str = String::from_utf8(request.api_request.body).unwrap();
324        let parsed: Value = serde_json::from_str(&body_str).unwrap();
325
326        assert!(parsed.get("valueRange").is_some());
327        assert!(parsed.get("spreadsheet_token").is_none()); // Should be skipped
328    }
329
330    #[test]
331    fn test_prepend_data_request_builder_overwrite_behavior() {
332        let mut builder = PrependDataRequest::builder();
333
334        // Test that subsequent calls overwrite previous values
335        builder = builder.spreadsheet_token("first_token");
336        builder = builder.spreadsheet_token("final_token");
337        builder = builder.range("first_range");
338        builder = builder.range("final_range");
339
340        let request = builder.build();
341
342        assert_eq!(request.spreadsheet_token, "final_token");
343        assert_eq!(request.value_range.range, "final_range");
344    }
345
346    #[test]
347    fn test_prepend_data_request_with_large_dataset() {
348        let large_data = json!((0..500)
349            .map(|i| vec![
350                format!("Item_{}", i),
351                format!("Category_{}", i % 10),
352                format!("Description for item number {}", i),
353                (i * 2).to_string(),
354            ])
355            .collect::<Vec<_>>());
356
357        let request = PrependDataRequest::builder()
358            .spreadsheet_token("large_dataset_token")
359            .range("BigSheet!A:D")
360            .values(large_data.clone())
361            .build();
362
363        assert_eq!(request.value_range.values, large_data);
364        assert_eq!(request.spreadsheet_token, "large_dataset_token");
365    }
366
367    #[test]
368    fn test_prepend_data_request_edge_cases() {
369        // Test with extremely long token
370        let very_long_token = "x".repeat(5000);
371        let request = PrependDataRequest::builder()
372            .spreadsheet_token(&very_long_token)
373            .build();
374        assert_eq!(request.spreadsheet_token, very_long_token);
375
376        // Test with empty array
377        let empty_array = json!([]);
378        let request = PrependDataRequest::builder()
379            .values(empty_array.clone())
380            .build();
381        assert_eq!(request.value_range.values, empty_array);
382
383        // Test with deeply nested structures
384        let nested_data = json!([[[[[["deep", "nesting"], ["test", "data"]]]]]]);
385        let request = PrependDataRequest::builder()
386            .values(nested_data.clone())
387            .build();
388        assert_eq!(request.value_range.values, nested_data);
389    }
390
391    #[test]
392    fn test_spreadsheet_sheet_service_creation() {
393        let service = create_test_service();
394        assert_eq!(service.config.app_id, "test_app_id");
395        assert_eq!(service.config.app_type, AppType::SelfBuild);
396    }
397
398    #[test]
399    fn test_prepend_data_response_type_alias() {
400        // Verify that PrependDataResponse is correctly aliased
401        let _response: PrependDataResponse = UpdateSheetDataResponse {
402            spreed_sheet_token: "prepend_test".to_string(),
403            table_range: "A1:B5".to_string(),
404            revision: 2,
405            updates: crate::service::cloud_docs::sheets::v2::data_operation::SheetDataUpdates {
406                spreed_sheet_token: "prepend_test".to_string(),
407                updated_range: "A1:B5".to_string(),
408                updated_rows: 5,
409                updated_columns: 2,
410                updated_cells: 10,
411                revision: Some(2),
412            },
413        };
414    }
415
416    #[test]
417    fn test_prepend_data_request_memory_efficiency() {
418        // Test creating multiple requests efficiently
419        let requests: Vec<PrependDataRequest> = (0..50)
420            .map(|i| {
421                PrependDataRequest::builder()
422                    .spreadsheet_token(format!("efficient_token_{}", i))
423                    .range(format!("Sheet{}!A:C", i + 1))
424                    .values(json!([[
425                        format!("Row{}", i),
426                        i.to_string(),
427                        format!("Data{}", i)
428                    ]]))
429                    .build()
430            })
431            .collect();
432
433        assert_eq!(requests.len(), 50);
434
435        // Verify data integrity across all requests
436        for (i, request) in requests.iter().enumerate() {
437            assert_eq!(request.spreadsheet_token, format!("efficient_token_{}", i));
438            assert_eq!(request.value_range.range, format!("Sheet{}!A:C", i + 1));
439        }
440    }
441
442    #[test]
443    fn test_value_range_request_within_prepend_context() {
444        let value_range = ValueRangeRequest {
445            range: "PrependTest!A1:B2".to_string(),
446            values: json!([["Prepend1", "Prepend2"]]),
447        };
448
449        let request = PrependDataRequest {
450            api_request: ApiRequest::default(),
451            spreadsheet_token: "vr_test".to_string(),
452            value_range,
453        };
454
455        assert_eq!(request.value_range.range, "PrependTest!A1:B2");
456        assert_eq!(
457            request.value_range.values,
458            json!([["Prepend1", "Prepend2"]])
459        );
460    }
461
462    #[test]
463    fn test_prepend_data_request_json_serialization_completeness() {
464        let comprehensive_data = json!([
465            ["Text", "Number", "Boolean", "Null", "Array", "Object"],
466            ["Sample", 42, true, null, [1, 2, 3], {"nested": "value"}],
467            ["Unicode: 中文", 3.14286, false, null, [], {}]
468        ]);
469
470        let request = PrependDataRequest::builder()
471            .spreadsheet_token("comprehensive_test")
472            .range("Complete!A1:F3")
473            .values(comprehensive_data.clone())
474            .build();
475
476        let serialized = serde_json::to_string(&request).unwrap();
477        let parsed: Value = serde_json::from_str(&serialized).unwrap();
478
479        assert_eq!(parsed["valueRange"]["values"], comprehensive_data);
480        assert_eq!(parsed["valueRange"]["range"], "Complete!A1:F3");
481    }
482}