open_lark/service/cloud_docs/bitable/v1/
share.rs

1use crate::service::bitable::v1::app_table_field::Person;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::collections::HashMap;
5
6#[derive(Debug, Default, Serialize, Deserialize, Clone)]
7pub struct Record {
8    pub fields: HashMap<String, Value>,
9    /// 记录Id
10    pub record_id: Option<String>,
11    /// 创建人
12    pub created_by: Option<Person>,
13    /// 创建时间
14    pub created_time: Option<u128>,
15    /// 修改人
16    pub last_modified_by: Option<Person>,
17    /// 最近更新时间
18    pub last_modified_time: Option<u128>,
19}
20
21impl Record {
22    pub fn from_json(json: Value) -> Self {
23        let obj = json.as_object().expect("json must be a object");
24        let mut fields = HashMap::new();
25        for (k, v) in obj.iter() {
26            fields.insert(k.clone(), v.clone());
27        }
28        Record {
29            fields,
30            record_id: None,
31            created_by: None,
32            created_time: None,
33            last_modified_by: None,
34            last_modified_time: None,
35        }
36    }
37}
38
39/// 一些帮助函数
40impl Record {
41    /// 获取文本
42    pub fn get_text(&self, key: &str) -> Option<String> {
43        let value = self.fields.get(key)?;
44        let array = value.as_array()?;
45        let first_item = array.first()?;
46        let text = first_item.get("text")?.as_str()?;
47        Some(text.to_string())
48    }
49
50    /// 获取数字
51    pub fn get_number(&self, key: &str) -> Option<f64> {
52        let value = self.fields.get(key)?;
53        let number = value.as_f64()?;
54        Some(number)
55    }
56
57    /// 获取数组文本
58    pub fn get_array_text(&self, key: &str) -> Option<Vec<String>> {
59        let value = self.fields.get(key)?;
60        let array = value.as_array()?;
61        let mut texts = Vec::new();
62        for item in array {
63            let text = item.as_str()?.to_string();
64            texts.push(text);
65        }
66        Some(texts)
67    }
68
69    /// 获取单选文本
70    pub fn get_single_select_text(&self, key: &str) -> Option<String> {
71        let value = self.fields.get(key)?;
72        let text = value.as_str()?;
73        Some(text.to_string())
74    }
75
76    /// 获取多选文本
77    pub fn get_multi_select_text(&self, key: &str) -> Option<Vec<String>> {
78        let value = self.fields.get(key)?;
79        let array = value.as_array()?;
80        let mut texts = Vec::new();
81        for item in array {
82            let text = item.as_str()?.to_string();
83            texts.push(text);
84        }
85        Some(texts)
86    }
87
88    /// 获取布尔值(通过 checkbox)
89    pub fn get_checkbox(&self, key: &str) -> Option<bool> {
90        let value = self.fields.get(key)?;
91        let checkbox = value.as_bool()?;
92        Some(checkbox)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use serde_json::json;
100
101    #[test]
102    fn test_record_default() {
103        let record = Record::default();
104        assert!(record.fields.is_empty());
105        assert!(record.record_id.is_none());
106        assert!(record.created_by.is_none());
107        assert!(record.created_time.is_none());
108        assert!(record.last_modified_by.is_none());
109        assert!(record.last_modified_time.is_none());
110    }
111
112    #[test]
113    fn test_record_debug() {
114        let record = Record::default();
115        let debug_str = format!("{:?}", record);
116        assert!(debug_str.contains("Record"));
117    }
118
119    #[test]
120    fn test_record_clone() {
121        let mut record = Record::default();
122        record.fields.insert("test".to_string(), json!("value"));
123        record.record_id = Some("rec123".to_string());
124
125        let cloned = record.clone();
126        assert_eq!(record.fields, cloned.fields);
127        assert_eq!(record.record_id, cloned.record_id);
128    }
129
130    #[test]
131    fn test_record_serialization() {
132        let mut record = Record::default();
133        record.fields.insert("name".to_string(), json!("Test"));
134        record.record_id = Some("rec_001".to_string());
135
136        let serialized = serde_json::to_string(&record).expect("Should serialize");
137        let deserialized: Record = serde_json::from_str(&serialized).expect("Should deserialize");
138
139        assert_eq!(record.fields, deserialized.fields);
140        assert_eq!(record.record_id, deserialized.record_id);
141    }
142
143    #[test]
144    fn test_record_from_json_simple() {
145        let json = json!({
146            "name": "John Doe",
147            "age": 30,
148            "active": true
149        });
150
151        let record = Record::from_json(json);
152        assert_eq!(record.fields.len(), 3);
153        assert_eq!(record.fields.get("name"), Some(&json!("John Doe")));
154        assert_eq!(record.fields.get("age"), Some(&json!(30)));
155        assert_eq!(record.fields.get("active"), Some(&json!(true)));
156    }
157
158    #[test]
159    fn test_record_from_json_empty() {
160        let json = json!({});
161        let record = Record::from_json(json);
162        assert!(record.fields.is_empty());
163        assert!(record.record_id.is_none());
164    }
165
166    #[test]
167    fn test_record_from_json_complex() {
168        let json = json!({
169            "text_field": "value",
170            "number_field": 42.5,
171            "array_field": ["item1", "item2"],
172            "object_field": {
173                "nested": "value"
174            }
175        });
176
177        let record = Record::from_json(json);
178        assert_eq!(record.fields.len(), 4);
179        assert_eq!(record.fields.get("text_field"), Some(&json!("value")));
180        assert_eq!(record.fields.get("number_field"), Some(&json!(42.5)));
181        assert_eq!(
182            record.fields.get("array_field"),
183            Some(&json!(["item1", "item2"]))
184        );
185        assert_eq!(
186            record.fields.get("object_field"),
187            Some(&json!({"nested": "value"}))
188        );
189    }
190
191    #[test]
192    #[should_panic(expected = "json must be a object")]
193    fn test_record_from_json_invalid_type() {
194        let json = json!("not an object");
195        Record::from_json(json);
196    }
197
198    #[test]
199    fn test_get_text() {
200        let mut record = Record::default();
201        record
202            .fields
203            .insert("text_field".to_string(), json!([{"text": "Hello World"}]));
204
205        let text = record.get_text("text_field");
206        assert_eq!(text, Some("Hello World".to_string()));
207    }
208
209    #[test]
210    fn test_get_text_nonexistent_key() {
211        let record = Record::default();
212        let text = record.get_text("nonexistent");
213        assert_eq!(text, None);
214    }
215
216    #[test]
217    fn test_get_text_invalid_format() {
218        let mut record = Record::default();
219        record
220            .fields
221            .insert("invalid".to_string(), json!("not an array"));
222
223        let text = record.get_text("invalid");
224        assert_eq!(text, None);
225    }
226
227    #[test]
228    fn test_get_text_empty_array() {
229        let mut record = Record::default();
230        record.fields.insert("empty_array".to_string(), json!([]));
231
232        let text = record.get_text("empty_array");
233        assert_eq!(text, None);
234    }
235
236    #[test]
237    fn test_get_text_missing_text_field() {
238        let mut record = Record::default();
239        record
240            .fields
241            .insert("no_text".to_string(), json!([{"value": "test"}]));
242
243        let text = record.get_text("no_text");
244        assert_eq!(text, None);
245    }
246
247    #[test]
248    fn test_get_number() {
249        let mut record = Record::default();
250        record
251            .fields
252            .insert("number_field".to_string(), json!(42.5));
253
254        let number = record.get_number("number_field");
255        assert_eq!(number, Some(42.5));
256    }
257
258    #[test]
259    fn test_get_number_integer() {
260        let mut record = Record::default();
261        record.fields.insert("int_field".to_string(), json!(42));
262
263        let number = record.get_number("int_field");
264        assert_eq!(number, Some(42.0));
265    }
266
267    #[test]
268    fn test_get_number_nonexistent() {
269        let record = Record::default();
270        let number = record.get_number("nonexistent");
271        assert_eq!(number, None);
272    }
273
274    #[test]
275    fn test_get_number_invalid_type() {
276        let mut record = Record::default();
277        record
278            .fields
279            .insert("text_field".to_string(), json!("not a number"));
280
281        let number = record.get_number("text_field");
282        assert_eq!(number, None);
283    }
284
285    #[test]
286    fn test_get_array_text() {
287        let mut record = Record::default();
288        record.fields.insert(
289            "array_field".to_string(),
290            json!(["item1", "item2", "item3"]),
291        );
292
293        let array = record.get_array_text("array_field");
294        assert_eq!(
295            array,
296            Some(vec![
297                "item1".to_string(),
298                "item2".to_string(),
299                "item3".to_string()
300            ])
301        );
302    }
303
304    #[test]
305    fn test_get_array_text_empty() {
306        let mut record = Record::default();
307        record.fields.insert("empty_array".to_string(), json!([]));
308
309        let array = record.get_array_text("empty_array");
310        assert_eq!(array, Some(vec![]));
311    }
312
313    #[test]
314    fn test_get_array_text_nonexistent() {
315        let record = Record::default();
316        let array = record.get_array_text("nonexistent");
317        assert_eq!(array, None);
318    }
319
320    #[test]
321    fn test_get_array_text_invalid_type() {
322        let mut record = Record::default();
323        record
324            .fields
325            .insert("not_array".to_string(), json!("string"));
326
327        let array = record.get_array_text("not_array");
328        assert_eq!(array, None);
329    }
330
331    #[test]
332    fn test_get_array_text_invalid_element() {
333        let mut record = Record::default();
334        record.fields.insert(
335            "mixed_array".to_string(),
336            json!(["valid", 123, "also_valid"]),
337        );
338
339        let array = record.get_array_text("mixed_array");
340        assert_eq!(array, None); // Should fail on the number element
341    }
342
343    #[test]
344    fn test_get_single_select_text() {
345        let mut record = Record::default();
346        record
347            .fields
348            .insert("select_field".to_string(), json!("Selected Option"));
349
350        let text = record.get_single_select_text("select_field");
351        assert_eq!(text, Some("Selected Option".to_string()));
352    }
353
354    #[test]
355    fn test_get_single_select_text_nonexistent() {
356        let record = Record::default();
357        let text = record.get_single_select_text("nonexistent");
358        assert_eq!(text, None);
359    }
360
361    #[test]
362    fn test_get_single_select_text_invalid_type() {
363        let mut record = Record::default();
364        record.fields.insert("number_field".to_string(), json!(42));
365
366        let text = record.get_single_select_text("number_field");
367        assert_eq!(text, None);
368    }
369
370    #[test]
371    fn test_get_multi_select_text() {
372        let mut record = Record::default();
373        record.fields.insert(
374            "multi_select".to_string(),
375            json!(["Option1", "Option2", "Option3"]),
376        );
377
378        let texts = record.get_multi_select_text("multi_select");
379        assert_eq!(
380            texts,
381            Some(vec![
382                "Option1".to_string(),
383                "Option2".to_string(),
384                "Option3".to_string()
385            ])
386        );
387    }
388
389    #[test]
390    fn test_get_multi_select_text_empty() {
391        let mut record = Record::default();
392        record.fields.insert("empty_multi".to_string(), json!([]));
393
394        let texts = record.get_multi_select_text("empty_multi");
395        assert_eq!(texts, Some(vec![]));
396    }
397
398    #[test]
399    fn test_get_multi_select_text_nonexistent() {
400        let record = Record::default();
401        let texts = record.get_multi_select_text("nonexistent");
402        assert_eq!(texts, None);
403    }
404
405    #[test]
406    fn test_get_multi_select_text_invalid_type() {
407        let mut record = Record::default();
408        record
409            .fields
410            .insert("string_field".to_string(), json!("not an array"));
411
412        let texts = record.get_multi_select_text("string_field");
413        assert_eq!(texts, None);
414    }
415
416    #[test]
417    fn test_get_multi_select_text_invalid_element() {
418        let mut record = Record::default();
419        record.fields.insert(
420            "mixed_multi".to_string(),
421            json!(["valid", 456, "also_valid"]),
422        );
423
424        let texts = record.get_multi_select_text("mixed_multi");
425        assert_eq!(texts, None); // Should fail on the number element
426    }
427
428    #[test]
429    fn test_get_checkbox() {
430        let mut record = Record::default();
431        record
432            .fields
433            .insert("checkbox_true".to_string(), json!(true));
434        record
435            .fields
436            .insert("checkbox_false".to_string(), json!(false));
437
438        let check_true = record.get_checkbox("checkbox_true");
439        let check_false = record.get_checkbox("checkbox_false");
440
441        assert_eq!(check_true, Some(true));
442        assert_eq!(check_false, Some(false));
443    }
444
445    #[test]
446    fn test_get_checkbox_nonexistent() {
447        let record = Record::default();
448        let checkbox = record.get_checkbox("nonexistent");
449        assert_eq!(checkbox, None);
450    }
451
452    #[test]
453    fn test_get_checkbox_invalid_type() {
454        let mut record = Record::default();
455        record
456            .fields
457            .insert("string_field".to_string(), json!("not a boolean"));
458
459        let checkbox = record.get_checkbox("string_field");
460        assert_eq!(checkbox, None);
461    }
462
463    #[test]
464    fn test_record_with_person_fields() {
465        let person = Person {
466            id: "person_123".to_string(),
467            name: "John Doe".to_string(),
468            en_name: "John Doe".to_string(),
469            email: "john@example.com".to_string(),
470        };
471
472        let record = Record {
473            fields: HashMap::new(),
474            record_id: Some("rec_456".to_string()),
475            created_by: Some(person.clone()),
476            created_time: Some(1640995200000),
477            last_modified_by: Some(person),
478            last_modified_time: Some(1640995260000),
479        };
480
481        assert_eq!(record.record_id, Some("rec_456".to_string()));
482        assert_eq!(record.created_time, Some(1640995200000));
483        assert_eq!(record.last_modified_time, Some(1640995260000));
484        assert!(record.created_by.is_some());
485        assert!(record.last_modified_by.is_some());
486    }
487
488    #[test]
489    fn test_record_comprehensive_field_access() {
490        let mut record = Record::default();
491        record
492            .fields
493            .insert("text_field".to_string(), json!([{"text": "Sample Text"}]));
494        record
495            .fields
496            .insert("number_field".to_string(), json!(123.45));
497        record
498            .fields
499            .insert("array_text".to_string(), json!(["A", "B", "C"]));
500        record
501            .fields
502            .insert("single_select".to_string(), json!("Option A"));
503        record
504            .fields
505            .insert("multi_select".to_string(), json!(["X", "Y", "Z"]));
506        record
507            .fields
508            .insert("checkbox_field".to_string(), json!(true));
509
510        // Test all helper methods
511        assert_eq!(
512            record.get_text("text_field"),
513            Some("Sample Text".to_string())
514        );
515        assert_eq!(record.get_number("number_field"), Some(123.45));
516        assert_eq!(
517            record.get_array_text("array_text"),
518            Some(vec!["A".to_string(), "B".to_string(), "C".to_string()])
519        );
520        assert_eq!(
521            record.get_single_select_text("single_select"),
522            Some("Option A".to_string())
523        );
524        assert_eq!(
525            record.get_multi_select_text("multi_select"),
526            Some(vec!["X".to_string(), "Y".to_string(), "Z".to_string()])
527        );
528        assert_eq!(record.get_checkbox("checkbox_field"), Some(true));
529    }
530
531    #[test]
532    fn test_record_with_unicode_content() {
533        let mut record = Record::default();
534        record
535            .fields
536            .insert("chinese_text".to_string(), json!([{"text": "你好世界"}]));
537        record
538            .fields
539            .insert("emoji_field".to_string(), json!("🚀💻🎉"));
540        record
541            .fields
542            .insert("unicode_array".to_string(), json!(["测试", "テスト", "🌟"]));
543
544        assert_eq!(
545            record.get_text("chinese_text"),
546            Some("你好世界".to_string())
547        );
548        assert_eq!(
549            record.get_single_select_text("emoji_field"),
550            Some("🚀💻🎉".to_string())
551        );
552        assert_eq!(
553            record.get_array_text("unicode_array"),
554            Some(vec![
555                "测试".to_string(),
556                "テスト".to_string(),
557                "🌟".to_string()
558            ])
559        );
560    }
561
562    #[test]
563    fn test_record_edge_cases() {
564        let mut record = Record::default();
565
566        // Empty string values
567        record
568            .fields
569            .insert("empty_text".to_string(), json!([{"text": ""}]));
570        record.fields.insert("empty_select".to_string(), json!(""));
571
572        // Zero values
573        record.fields.insert("zero_number".to_string(), json!(0));
574        record.fields.insert("zero_float".to_string(), json!(0.0));
575
576        assert_eq!(record.get_text("empty_text"), Some("".to_string()));
577        assert_eq!(
578            record.get_single_select_text("empty_select"),
579            Some("".to_string())
580        );
581        assert_eq!(record.get_number("zero_number"), Some(0.0));
582        assert_eq!(record.get_number("zero_float"), Some(0.0));
583    }
584
585    #[test]
586    fn test_record_memory_efficiency() {
587        let record = Record::default();
588        let size = std::mem::size_of_val(&record);
589
590        // Should be reasonably sized
591        assert!(size > 0);
592        assert!(size < 1024); // Should be less than 1KB for empty record
593    }
594
595    #[test]
596    fn test_record_large_data() {
597        let mut record = Record::default();
598
599        // Large text field
600        let large_text = "x".repeat(10000);
601        record.fields.insert(
602            "large_field".to_string(),
603            json!([{"text": large_text.clone()}]),
604        );
605
606        // Large array
607        let large_array: Vec<String> = (0..1000).map(|i| format!("item_{}", i)).collect();
608        record
609            .fields
610            .insert("large_array".to_string(), json!(large_array.clone()));
611
612        assert_eq!(record.get_text("large_field"), Some(large_text));
613        assert_eq!(record.get_array_text("large_array"), Some(large_array));
614    }
615}