nylas_types/
contact.rs

1//! Contact types for Nylas API v3
2//!
3//! Contacts represent people and organizations in email and calendar systems.
4
5use serde::{Deserialize, Serialize};
6
7use crate::common::{ContactId, GrantId};
8
9/// A contact entry.
10///
11/// Represents a person or organization with contact information.
12///
13/// # Example
14///
15/// ```
16/// # use nylas_types::{Contact, ContactId, GrantId};
17/// let contact = Contact {
18///     id: ContactId::new("contact_123"),
19///     grant_id: GrantId::new("grant_456"),
20///     given_name: Some("John".to_string()),
21///     family_name: Some("Doe".to_string()),
22///     emails: vec![],
23///     phone_numbers: vec![],
24///     physical_addresses: vec![],
25///     web_pages: vec![],
26///     groups: vec![],
27///     middle_name: None,
28///     suffix: None,
29///     nickname: None,
30///     birthday: None,
31///     company_name: None,
32///     job_title: None,
33///     manager_name: None,
34///     office_location: None,
35///     notes: None,
36///     picture_url: None,
37///     picture: None,
38/// };
39/// ```
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41pub struct Contact {
42    /// Unique identifier for the contact.
43    pub id: ContactId,
44
45    /// Grant ID this contact belongs to.
46    pub grant_id: GrantId,
47
48    /// Contact's given name (first name).
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub given_name: Option<String>,
51
52    /// Contact's middle name.
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub middle_name: Option<String>,
55
56    /// Contact's family name (last name).
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub family_name: Option<String>,
59
60    /// Name suffix (e.g., "Jr.", "Sr.", "III").
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub suffix: Option<String>,
63
64    /// Contact's nickname.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub nickname: Option<String>,
67
68    /// Birthday in YYYY-MM-DD format.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub birthday: Option<String>,
71
72    /// Company name.
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub company_name: Option<String>,
75
76    /// Job title.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub job_title: Option<String>,
79
80    /// Manager's name.
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub manager_name: Option<String>,
83
84    /// Office location.
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub office_location: Option<String>,
87
88    /// Notes about the contact.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub notes: Option<String>,
91
92    /// URL to contact's picture.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub picture_url: Option<String>,
95
96    /// Base64-encoded contact picture.
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub picture: Option<String>,
99
100    /// List of email addresses.
101    #[serde(default)]
102    pub emails: Vec<ContactEmail>,
103
104    /// List of phone numbers.
105    #[serde(default)]
106    pub phone_numbers: Vec<ContactPhone>,
107
108    /// List of physical addresses.
109    #[serde(default)]
110    pub physical_addresses: Vec<ContactAddress>,
111
112    /// List of web pages.
113    #[serde(default)]
114    pub web_pages: Vec<ContactWebPage>,
115
116    /// List of groups this contact belongs to.
117    #[serde(default)]
118    pub groups: Vec<ContactGroup>,
119}
120
121/// An email address for a contact.
122#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
123pub struct ContactEmail {
124    /// Email address type (e.g., "work", "home", "other").
125    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
126    pub email_type: Option<String>,
127
128    /// The email address.
129    pub email: String,
130}
131
132/// A phone number for a contact.
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub struct ContactPhone {
135    /// Phone number type (e.g., "work", "home", "mobile", "other").
136    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
137    pub phone_type: Option<String>,
138
139    /// The phone number.
140    pub number: String,
141}
142
143/// A physical address for a contact.
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
145pub struct ContactAddress {
146    /// Address type (e.g., "work", "home", "other").
147    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
148    pub address_type: Option<String>,
149
150    /// Street address.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub street_address: Option<String>,
153
154    /// City.
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub city: Option<String>,
157
158    /// State or province.
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub state: Option<String>,
161
162    /// Postal code.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub postal_code: Option<String>,
165
166    /// Country.
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub country: Option<String>,
169}
170
171/// A web page for a contact.
172#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
173pub struct ContactWebPage {
174    /// Web page type (e.g., "homepage", "blog", "profile", "other").
175    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
176    pub page_type: Option<String>,
177
178    /// The URL.
179    pub url: String,
180}
181
182/// A group that a contact belongs to.
183#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
184pub struct ContactGroup {
185    /// Group ID.
186    pub id: String,
187
188    /// Group name.
189    #[serde(skip_serializing_if = "Option::is_none")]
190    pub name: Option<String>,
191
192    /// Group path.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub path: Option<String>,
195}
196
197/// Request to create a new contact.
198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
199pub struct CreateContactRequest {
200    /// Contact's given name (first name).
201    #[serde(skip_serializing_if = "Option::is_none")]
202    pub given_name: Option<String>,
203
204    /// Contact's middle name.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub middle_name: Option<String>,
207
208    /// Contact's family name (last name).
209    #[serde(skip_serializing_if = "Option::is_none")]
210    pub family_name: Option<String>,
211
212    /// Name suffix.
213    #[serde(skip_serializing_if = "Option::is_none")]
214    pub suffix: Option<String>,
215
216    /// Contact's nickname.
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub nickname: Option<String>,
219
220    /// Birthday in YYYY-MM-DD format.
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub birthday: Option<String>,
223
224    /// Company name.
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub company_name: Option<String>,
227
228    /// Job title.
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub job_title: Option<String>,
231
232    /// Manager's name.
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub manager_name: Option<String>,
235
236    /// Office location.
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub office_location: Option<String>,
239
240    /// Notes about the contact.
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub notes: Option<String>,
243
244    /// URL to contact's picture.
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub picture_url: Option<String>,
247
248    /// Base64-encoded contact picture.
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub picture: Option<String>,
251
252    /// List of email addresses.
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub emails: Option<Vec<ContactEmail>>,
255
256    /// List of phone numbers.
257    #[serde(skip_serializing_if = "Option::is_none")]
258    pub phone_numbers: Option<Vec<ContactPhone>>,
259
260    /// List of physical addresses.
261    #[serde(skip_serializing_if = "Option::is_none")]
262    pub physical_addresses: Option<Vec<ContactAddress>>,
263
264    /// List of web pages.
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub web_pages: Option<Vec<ContactWebPage>>,
267
268    /// List of groups this contact belongs to.
269    #[serde(skip_serializing_if = "Option::is_none")]
270    pub groups: Option<Vec<ContactGroup>>,
271}
272
273impl CreateContactRequest {
274    /// Create a builder for CreateContactRequest.
275    pub fn builder() -> CreateContactRequestBuilder {
276        CreateContactRequestBuilder::default()
277    }
278}
279
280/// Builder for CreateContactRequest.
281#[derive(Debug, Clone, Default)]
282pub struct CreateContactRequestBuilder {
283    given_name: Option<String>,
284    middle_name: Option<String>,
285    family_name: Option<String>,
286    suffix: Option<String>,
287    nickname: Option<String>,
288    birthday: Option<String>,
289    company_name: Option<String>,
290    job_title: Option<String>,
291    manager_name: Option<String>,
292    office_location: Option<String>,
293    notes: Option<String>,
294    picture_url: Option<String>,
295    picture: Option<String>,
296    emails: Option<Vec<ContactEmail>>,
297    phone_numbers: Option<Vec<ContactPhone>>,
298    physical_addresses: Option<Vec<ContactAddress>>,
299    web_pages: Option<Vec<ContactWebPage>>,
300    groups: Option<Vec<ContactGroup>>,
301}
302
303impl CreateContactRequestBuilder {
304    /// Set given name.
305    pub fn given_name(mut self, name: impl Into<String>) -> Self {
306        self.given_name = Some(name.into());
307        self
308    }
309
310    /// Set middle name.
311    pub fn middle_name(mut self, name: impl Into<String>) -> Self {
312        self.middle_name = Some(name.into());
313        self
314    }
315
316    /// Set family name.
317    pub fn family_name(mut self, name: impl Into<String>) -> Self {
318        self.family_name = Some(name.into());
319        self
320    }
321
322    /// Set suffix.
323    pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
324        self.suffix = Some(suffix.into());
325        self
326    }
327
328    /// Set nickname.
329    pub fn nickname(mut self, nickname: impl Into<String>) -> Self {
330        self.nickname = Some(nickname.into());
331        self
332    }
333
334    /// Set birthday (YYYY-MM-DD format).
335    pub fn birthday(mut self, birthday: impl Into<String>) -> Self {
336        self.birthday = Some(birthday.into());
337        self
338    }
339
340    /// Set company name.
341    pub fn company_name(mut self, name: impl Into<String>) -> Self {
342        self.company_name = Some(name.into());
343        self
344    }
345
346    /// Set job title.
347    pub fn job_title(mut self, title: impl Into<String>) -> Self {
348        self.job_title = Some(title.into());
349        self
350    }
351
352    /// Set manager name.
353    pub fn manager_name(mut self, name: impl Into<String>) -> Self {
354        self.manager_name = Some(name.into());
355        self
356    }
357
358    /// Set office location.
359    pub fn office_location(mut self, location: impl Into<String>) -> Self {
360        self.office_location = Some(location.into());
361        self
362    }
363
364    /// Set notes.
365    pub fn notes(mut self, notes: impl Into<String>) -> Self {
366        self.notes = Some(notes.into());
367        self
368    }
369
370    /// Set picture URL.
371    pub fn picture_url(mut self, url: impl Into<String>) -> Self {
372        self.picture_url = Some(url.into());
373        self
374    }
375
376    /// Set picture (base64-encoded).
377    pub fn picture(mut self, picture: impl Into<String>) -> Self {
378        self.picture = Some(picture.into());
379        self
380    }
381
382    /// Set email addresses.
383    pub fn emails(mut self, emails: Vec<ContactEmail>) -> Self {
384        self.emails = Some(emails);
385        self
386    }
387
388    /// Set phone numbers.
389    pub fn phone_numbers(mut self, phones: Vec<ContactPhone>) -> Self {
390        self.phone_numbers = Some(phones);
391        self
392    }
393
394    /// Set physical addresses.
395    pub fn physical_addresses(mut self, addresses: Vec<ContactAddress>) -> Self {
396        self.physical_addresses = Some(addresses);
397        self
398    }
399
400    /// Set web pages.
401    pub fn web_pages(mut self, pages: Vec<ContactWebPage>) -> Self {
402        self.web_pages = Some(pages);
403        self
404    }
405
406    /// Set groups.
407    pub fn groups(mut self, groups: Vec<ContactGroup>) -> Self {
408        self.groups = Some(groups);
409        self
410    }
411
412    /// Build the CreateContactRequest.
413    pub fn build(self) -> CreateContactRequest {
414        CreateContactRequest {
415            given_name: self.given_name,
416            middle_name: self.middle_name,
417            family_name: self.family_name,
418            suffix: self.suffix,
419            nickname: self.nickname,
420            birthday: self.birthday,
421            company_name: self.company_name,
422            job_title: self.job_title,
423            manager_name: self.manager_name,
424            office_location: self.office_location,
425            notes: self.notes,
426            picture_url: self.picture_url,
427            picture: self.picture,
428            emails: self.emails,
429            phone_numbers: self.phone_numbers,
430            physical_addresses: self.physical_addresses,
431            web_pages: self.web_pages,
432            groups: self.groups,
433        }
434    }
435}
436
437/// Request to update a contact.
438#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
439pub struct UpdateContactRequest {
440    /// Update given name.
441    #[serde(skip_serializing_if = "Option::is_none")]
442    pub given_name: Option<String>,
443
444    /// Update middle name.
445    #[serde(skip_serializing_if = "Option::is_none")]
446    pub middle_name: Option<String>,
447
448    /// Update family name.
449    #[serde(skip_serializing_if = "Option::is_none")]
450    pub family_name: Option<String>,
451
452    /// Update suffix.
453    #[serde(skip_serializing_if = "Option::is_none")]
454    pub suffix: Option<String>,
455
456    /// Update nickname.
457    #[serde(skip_serializing_if = "Option::is_none")]
458    pub nickname: Option<String>,
459
460    /// Update birthday.
461    #[serde(skip_serializing_if = "Option::is_none")]
462    pub birthday: Option<String>,
463
464    /// Update company name.
465    #[serde(skip_serializing_if = "Option::is_none")]
466    pub company_name: Option<String>,
467
468    /// Update job title.
469    #[serde(skip_serializing_if = "Option::is_none")]
470    pub job_title: Option<String>,
471
472    /// Update manager name.
473    #[serde(skip_serializing_if = "Option::is_none")]
474    pub manager_name: Option<String>,
475
476    /// Update office location.
477    #[serde(skip_serializing_if = "Option::is_none")]
478    pub office_location: Option<String>,
479
480    /// Update notes.
481    #[serde(skip_serializing_if = "Option::is_none")]
482    pub notes: Option<String>,
483
484    /// Update picture URL.
485    #[serde(skip_serializing_if = "Option::is_none")]
486    pub picture_url: Option<String>,
487
488    /// Update picture.
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub picture: Option<String>,
491
492    /// Update email addresses.
493    #[serde(skip_serializing_if = "Option::is_none")]
494    pub emails: Option<Vec<ContactEmail>>,
495
496    /// Update phone numbers.
497    #[serde(skip_serializing_if = "Option::is_none")]
498    pub phone_numbers: Option<Vec<ContactPhone>>,
499
500    /// Update physical addresses.
501    #[serde(skip_serializing_if = "Option::is_none")]
502    pub physical_addresses: Option<Vec<ContactAddress>>,
503
504    /// Update web pages.
505    #[serde(skip_serializing_if = "Option::is_none")]
506    pub web_pages: Option<Vec<ContactWebPage>>,
507
508    /// Update groups.
509    #[serde(skip_serializing_if = "Option::is_none")]
510    pub groups: Option<Vec<ContactGroup>>,
511}
512
513impl UpdateContactRequest {
514    /// Create a builder for UpdateContactRequest.
515    pub fn builder() -> UpdateContactRequestBuilder {
516        UpdateContactRequestBuilder::default()
517    }
518}
519
520/// Builder for UpdateContactRequest.
521#[derive(Debug, Clone, Default)]
522pub struct UpdateContactRequestBuilder {
523    given_name: Option<String>,
524    middle_name: Option<String>,
525    family_name: Option<String>,
526    suffix: Option<String>,
527    nickname: Option<String>,
528    birthday: Option<String>,
529    company_name: Option<String>,
530    job_title: Option<String>,
531    manager_name: Option<String>,
532    office_location: Option<String>,
533    notes: Option<String>,
534    picture_url: Option<String>,
535    picture: Option<String>,
536    emails: Option<Vec<ContactEmail>>,
537    phone_numbers: Option<Vec<ContactPhone>>,
538    physical_addresses: Option<Vec<ContactAddress>>,
539    web_pages: Option<Vec<ContactWebPage>>,
540    groups: Option<Vec<ContactGroup>>,
541}
542
543impl UpdateContactRequestBuilder {
544    /// Set given name.
545    pub fn given_name(mut self, name: impl Into<String>) -> Self {
546        self.given_name = Some(name.into());
547        self
548    }
549
550    /// Set middle name.
551    pub fn middle_name(mut self, name: impl Into<String>) -> Self {
552        self.middle_name = Some(name.into());
553        self
554    }
555
556    /// Set family name.
557    pub fn family_name(mut self, name: impl Into<String>) -> Self {
558        self.family_name = Some(name.into());
559        self
560    }
561
562    /// Set suffix.
563    pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
564        self.suffix = Some(suffix.into());
565        self
566    }
567
568    /// Set nickname.
569    pub fn nickname(mut self, nickname: impl Into<String>) -> Self {
570        self.nickname = Some(nickname.into());
571        self
572    }
573
574    /// Set birthday.
575    pub fn birthday(mut self, birthday: impl Into<String>) -> Self {
576        self.birthday = Some(birthday.into());
577        self
578    }
579
580    /// Set company name.
581    pub fn company_name(mut self, name: impl Into<String>) -> Self {
582        self.company_name = Some(name.into());
583        self
584    }
585
586    /// Set job title.
587    pub fn job_title(mut self, title: impl Into<String>) -> Self {
588        self.job_title = Some(title.into());
589        self
590    }
591
592    /// Set manager name.
593    pub fn manager_name(mut self, name: impl Into<String>) -> Self {
594        self.manager_name = Some(name.into());
595        self
596    }
597
598    /// Set office location.
599    pub fn office_location(mut self, location: impl Into<String>) -> Self {
600        self.office_location = Some(location.into());
601        self
602    }
603
604    /// Set notes.
605    pub fn notes(mut self, notes: impl Into<String>) -> Self {
606        self.notes = Some(notes.into());
607        self
608    }
609
610    /// Set picture URL.
611    pub fn picture_url(mut self, url: impl Into<String>) -> Self {
612        self.picture_url = Some(url.into());
613        self
614    }
615
616    /// Set picture.
617    pub fn picture(mut self, picture: impl Into<String>) -> Self {
618        self.picture = Some(picture.into());
619        self
620    }
621
622    /// Set emails.
623    pub fn emails(mut self, emails: Vec<ContactEmail>) -> Self {
624        self.emails = Some(emails);
625        self
626    }
627
628    /// Set phone numbers.
629    pub fn phone_numbers(mut self, phones: Vec<ContactPhone>) -> Self {
630        self.phone_numbers = Some(phones);
631        self
632    }
633
634    /// Set physical addresses.
635    pub fn physical_addresses(mut self, addresses: Vec<ContactAddress>) -> Self {
636        self.physical_addresses = Some(addresses);
637        self
638    }
639
640    /// Set web pages.
641    pub fn web_pages(mut self, pages: Vec<ContactWebPage>) -> Self {
642        self.web_pages = Some(pages);
643        self
644    }
645
646    /// Set groups.
647    pub fn groups(mut self, groups: Vec<ContactGroup>) -> Self {
648        self.groups = Some(groups);
649        self
650    }
651
652    /// Build the UpdateContactRequest.
653    pub fn build(self) -> UpdateContactRequest {
654        UpdateContactRequest {
655            given_name: self.given_name,
656            middle_name: self.middle_name,
657            family_name: self.family_name,
658            suffix: self.suffix,
659            nickname: self.nickname,
660            birthday: self.birthday,
661            company_name: self.company_name,
662            job_title: self.job_title,
663            manager_name: self.manager_name,
664            office_location: self.office_location,
665            notes: self.notes,
666            picture_url: self.picture_url,
667            picture: self.picture,
668            emails: self.emails,
669            phone_numbers: self.phone_numbers,
670            physical_addresses: self.physical_addresses,
671            web_pages: self.web_pages,
672            groups: self.groups,
673        }
674    }
675}
676
677#[cfg(test)]
678mod tests {
679    use super::*;
680
681    #[test]
682    fn test_contact_creation() {
683        let contact = Contact {
684            id: ContactId::new("contact_123"),
685            grant_id: GrantId::new("grant_456"),
686            given_name: Some("John".to_string()),
687            family_name: Some("Doe".to_string()),
688            emails: vec![ContactEmail {
689                email_type: Some("work".to_string()),
690                email: "john.doe@example.com".to_string(),
691            }],
692            phone_numbers: vec![],
693            physical_addresses: vec![],
694            web_pages: vec![],
695            groups: vec![],
696            middle_name: None,
697            suffix: None,
698            nickname: None,
699            birthday: None,
700            company_name: None,
701            job_title: None,
702            manager_name: None,
703            office_location: None,
704            notes: None,
705            picture_url: None,
706            picture: None,
707        };
708
709        assert_eq!(contact.id.as_str(), "contact_123");
710        assert_eq!(contact.given_name.as_ref().unwrap(), "John");
711        assert_eq!(contact.family_name.as_ref().unwrap(), "Doe");
712        assert_eq!(contact.emails.len(), 1);
713    }
714
715    #[test]
716    fn test_contact_serialization() {
717        let contact = Contact {
718            id: ContactId::new("contact_123"),
719            grant_id: GrantId::new("grant_456"),
720            given_name: Some("Jane".to_string()),
721            family_name: Some("Smith".to_string()),
722            emails: vec![],
723            phone_numbers: vec![],
724            physical_addresses: vec![],
725            web_pages: vec![],
726            groups: vec![],
727            middle_name: None,
728            suffix: None,
729            nickname: None,
730            birthday: None,
731            company_name: Some("Acme Corp".to_string()),
732            job_title: Some("Engineer".to_string()),
733            manager_name: None,
734            office_location: None,
735            notes: None,
736            picture_url: None,
737            picture: None,
738        };
739
740        let json = serde_json::to_string(&contact).unwrap();
741        assert!(json.contains("contact_123"));
742        assert!(json.contains("Jane"));
743        assert!(json.contains("Acme Corp"));
744    }
745
746    #[test]
747    fn test_contact_deserialization() {
748        let json = r#"{
749            "id": "contact_123",
750            "grant_id": "grant_456",
751            "given_name": "Bob",
752            "family_name": "Johnson",
753            "company_name": "Tech Inc",
754            "emails": [],
755            "phone_numbers": [],
756            "physical_addresses": [],
757            "web_pages": [],
758            "groups": []
759        }"#;
760
761        let contact: Contact = serde_json::from_str(json).unwrap();
762        assert_eq!(contact.id.as_str(), "contact_123");
763        assert_eq!(contact.given_name.as_ref().unwrap(), "Bob");
764        assert_eq!(contact.company_name.as_ref().unwrap(), "Tech Inc");
765    }
766
767    #[test]
768    fn test_create_contact_request_builder() {
769        let request = CreateContactRequest::builder()
770            .given_name("Alice")
771            .family_name("Williams")
772            .company_name("Example LLC")
773            .job_title("Manager")
774            .build();
775
776        assert_eq!(request.given_name.as_ref().unwrap(), "Alice");
777        assert_eq!(request.family_name.as_ref().unwrap(), "Williams");
778        assert_eq!(request.company_name.as_ref().unwrap(), "Example LLC");
779        assert_eq!(request.job_title.as_ref().unwrap(), "Manager");
780    }
781
782    #[test]
783    fn test_update_contact_request_builder() {
784        let update = UpdateContactRequest::builder()
785            .given_name("Updated Name")
786            .job_title("Senior Engineer")
787            .build();
788
789        assert_eq!(update.given_name.as_ref().unwrap(), "Updated Name");
790        assert_eq!(update.job_title.as_ref().unwrap(), "Senior Engineer");
791        assert!(update.company_name.is_none());
792    }
793
794    #[test]
795    fn test_contact_email() {
796        let email = ContactEmail {
797            email_type: Some("work".to_string()),
798            email: "test@example.com".to_string(),
799        };
800
801        assert_eq!(email.email_type.as_ref().unwrap(), "work");
802        assert_eq!(email.email, "test@example.com");
803    }
804
805    #[test]
806    fn test_contact_phone() {
807        let phone = ContactPhone {
808            phone_type: Some("mobile".to_string()),
809            number: "+1234567890".to_string(),
810        };
811
812        assert_eq!(phone.phone_type.as_ref().unwrap(), "mobile");
813        assert_eq!(phone.number, "+1234567890");
814    }
815
816    #[test]
817    fn test_contact_address() {
818        let address = ContactAddress {
819            address_type: Some("home".to_string()),
820            street_address: Some("123 Main St".to_string()),
821            city: Some("Springfield".to_string()),
822            state: Some("IL".to_string()),
823            postal_code: Some("62701".to_string()),
824            country: Some("USA".to_string()),
825        };
826
827        assert_eq!(address.address_type.as_ref().unwrap(), "home");
828        assert_eq!(address.city.as_ref().unwrap(), "Springfield");
829    }
830}