phenopacket_builder/v2/core/
individual.rs

1use crate::{Build, Buildable, Set, Unset};
2use phenopackets::schema::v2::core::time_element::Element;
3use phenopackets::schema::v2::core::vital_status::Status;
4use phenopackets::schema::v2::core::{
5    Age, GestationalAge, Individual, KaryotypicSex, OntologyClass, Sex, TimeElement, VitalStatus,
6};
7use std::marker::PhantomData;
8
9#[derive(Debug, Default, Clone, PartialEq)]
10pub struct IndividualBuilder<T = Unset> {
11    id: Option<String>,
12    alternate_ids: Vec<String>,
13    date_of_birth: Option<prost_types::Timestamp>,
14    time_at_last_encounter: Option<TimeElement>,
15    vital_status: Option<VitalStatus>,
16    sex: Sex,
17    karyotypic_sex: KaryotypicSex,
18    gender: Option<OntologyClass>,
19    taxonomy: Option<OntologyClass>,
20    data: PhantomData<T>,
21}
22
23impl<T> IndividualBuilder<T> {
24    pub fn add_alternate_id(mut self, id: impl Into<String>) -> Self {
25        self.alternate_ids.push(id.into());
26        self
27    }
28
29    pub fn extend_alternate_ids(
30        mut self,
31        ids: impl IntoIterator<Item = impl Into<String>>,
32    ) -> Self {
33        self.alternate_ids.extend(ids.into_iter().map(Into::into));
34        self
35    }
36
37    pub fn clear_alternate_ids(mut self) -> Self {
38        self.alternate_ids.clear();
39        self
40    }
41
42    pub fn date_of_birth(mut self, date: impl Build<prost_types::Timestamp>) -> Self {
43        self.date_of_birth = Some(date.build());
44        self
45    }
46
47    pub fn time_at_last_encounter(
48        mut self,
49        time_at_last_encounter: impl Build<TimeElement>,
50    ) -> Self {
51        self.time_at_last_encounter = Some(time_at_last_encounter.build());
52        self
53    }
54
55    pub fn vital_status(mut self, vital_status: impl Build<VitalStatus>) -> Self {
56        self.vital_status = Some(vital_status.build());
57        self
58    }
59
60    pub fn deceased(mut self) -> Self {
61        self.vital_status = Some(VitalStatus::builder().deceased().build());
62        self
63    }
64
65    pub fn deceased_at(mut self, time_of_death: impl Into<TimeElement>) -> Self {
66        self.vital_status = Some(
67            VitalStatus::builder()
68                .deceased()
69                .time_of_death(time_of_death)
70                .build(),
71        );
72        self
73    }
74
75    pub fn alive(mut self) -> Self {
76        self.vital_status = Some(VitalStatus::builder().alive().build());
77        self
78    }
79
80    pub fn sex(mut self, sex: impl Into<Sex>) -> Self {
81        self.sex = sex.into();
82        self
83    }
84
85    pub fn male(self) -> Self {
86        self.sex(Sex::Male)
87    }
88
89    pub fn female(self) -> Self {
90        self.sex(Sex::Female)
91    }
92
93    pub fn other_sex(self) -> Self {
94        self.sex(Sex::OtherSex)
95    }
96
97    pub fn karyotypic_sex(mut self, karyotypic_sex: impl Into<KaryotypicSex>) -> Self {
98        self.karyotypic_sex = karyotypic_sex.into();
99        self
100    }
101
102    pub fn karyotypic_sex_xx(self) -> Self {
103        self.karyotypic_sex(KaryotypicSex::Xx)
104    }
105
106    pub fn karyotypic_sex_xy(self) -> Self {
107        self.karyotypic_sex(KaryotypicSex::Xy)
108    }
109
110    pub fn karyotypic_sex_xo(self) -> Self {
111        self.karyotypic_sex(KaryotypicSex::Xo)
112    }
113
114    pub fn karyotypic_sex_xxy(self) -> Self {
115        self.karyotypic_sex(KaryotypicSex::Xxy)
116    }
117
118    pub fn karyotypic_sex_xxyy(self) -> Self {
119        self.karyotypic_sex(KaryotypicSex::Xxyy)
120    }
121
122    pub fn karyotypic_sex_xxxy(self) -> Self {
123        self.karyotypic_sex(KaryotypicSex::Xxxy)
124    }
125
126    pub fn karyotypic_sex_xxxx(self) -> Self {
127        self.karyotypic_sex(KaryotypicSex::Xxxx)
128    }
129
130    pub fn karyotypic_sex_xyy(self) -> Self {
131        self.karyotypic_sex(KaryotypicSex::Xyy)
132    }
133
134    pub fn karyotypic_sex_other(self) -> Self {
135        self.karyotypic_sex(KaryotypicSex::OtherKaryotype)
136    }
137
138    pub fn gender(mut self, gender: impl Build<OntologyClass>) -> Self {
139        self.gender = Some(gender.build());
140        self
141    }
142
143    pub fn taxonomy(mut self, taxonomy: impl Build<OntologyClass>) -> Self {
144        self.taxonomy = Some(taxonomy.build());
145        self
146    }
147
148    pub fn homo_sapiens(self) -> Self {
149        self.taxonomy(OntologyClass::builder().id_label("NCBITaxon:9606", "homo sapiens"))
150    }
151}
152
153impl IndividualBuilder<Unset> {
154    pub fn id(self, id: impl Into<String>) -> IndividualBuilder<Set> {
155        IndividualBuilder {
156            id: Some(id.into()),
157            alternate_ids: self.alternate_ids,
158            date_of_birth: self.date_of_birth,
159            time_at_last_encounter: self.time_at_last_encounter,
160            vital_status: self.vital_status,
161            sex: self.sex,
162            karyotypic_sex: self.karyotypic_sex,
163            gender: self.gender,
164            taxonomy: self.taxonomy,
165            data: PhantomData,
166        }
167    }
168}
169impl Buildable for Individual {
170    type Builder = IndividualBuilder;
171}
172
173impl Build<Individual> for IndividualBuilder<Set> {
174    fn build(self) -> Individual {
175        Individual {
176            id: self.id.expect("id must have been set"),
177            alternate_ids: self.alternate_ids,
178            date_of_birth: self.date_of_birth,
179            time_at_last_encounter: self.time_at_last_encounter,
180            vital_status: self.vital_status,
181            sex: self.sex.into(),
182            karyotypic_sex: self.karyotypic_sex.into(),
183            gender: self.gender,
184            taxonomy: self.taxonomy,
185        }
186    }
187}
188
189#[derive(Debug, Default, Clone, PartialEq)]
190pub struct VitalStatusBuilder<T = Unset> {
191    status: Option<Status>,
192    time_of_death: Option<TimeElement>,
193    cause_of_death: Option<OntologyClass>,
194    survival_time_in_days: Option<u32>,
195    data: PhantomData<T>,
196}
197
198impl<T> VitalStatusBuilder<T> {
199    pub fn status(self, status: impl Into<Status>) -> VitalStatusBuilder<Set> {
200        VitalStatusBuilder {
201            status: Some(status.into()),
202            time_of_death: self.time_of_death,
203            cause_of_death: self.cause_of_death,
204            survival_time_in_days: self.survival_time_in_days,
205            data: PhantomData,
206        }
207    }
208
209    pub fn alive(self) -> VitalStatusBuilder<Set> {
210        self.status(Status::Alive)
211    }
212
213    pub fn deceased(self) -> VitalStatusBuilder<Set> {
214        self.status(Status::Deceased)
215    }
216
217    pub fn time_of_death(mut self, time_of_death: impl Into<TimeElement>) -> VitalStatusBuilder<T> {
218        self.time_of_death = Some(time_of_death.into());
219        self
220    }
221
222    pub fn time_of_death_at_age(mut self, age: impl Into<Age>) -> VitalStatusBuilder<T> {
223        self.time_of_death = Some(TimeElement {
224            element: Some(Element::Age(age.into())),
225        });
226        self
227    }
228
229    pub fn time_of_death_at_gestational_age(
230        mut self,
231        gestational_age: impl Into<GestationalAge>,
232    ) -> VitalStatusBuilder<T> {
233        self.time_of_death = Some(TimeElement {
234            element: Some(Element::GestationalAge(gestational_age.into())),
235        });
236        self
237    }
238
239    pub fn cause_of_death(
240        mut self,
241        cause_of_death: impl Into<OntologyClass>,
242    ) -> VitalStatusBuilder<T> {
243        self.cause_of_death = Some(cause_of_death.into());
244        self
245    }
246
247    pub fn survival_time_in_days(
248        mut self,
249        survival_time_in_days: impl Into<u32>,
250    ) -> VitalStatusBuilder<T> {
251        self.survival_time_in_days = Some(survival_time_in_days.into());
252        self
253    }
254}
255
256impl Buildable for VitalStatus {
257    type Builder = VitalStatusBuilder;
258}
259
260impl Build<VitalStatus> for VitalStatusBuilder<Set> {
261    fn build(self) -> VitalStatus {
262        VitalStatus {
263            status: self.status.expect("status must have been set").into(),
264            time_of_death: self.time_of_death,
265            cause_of_death: self.cause_of_death,
266            survival_time_in_days: self.survival_time_in_days.unwrap_or_default(),
267        }
268    }
269}