storage/service_line/
training.rs1use serde::{Deserialize, Deserializer, Serialize};
8
9use domain::training::program;
10
11use crate::operations::{self, StorageField};
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(transparent)]
16pub struct ContractRecord(pub domain::training::Contract);
17
18impl From<domain::training::Contract> for ContractRecord {
19 fn from(value: domain::training::Contract) -> Self {
20 Self(value)
21 }
22}
23
24impl From<ContractRecord> for domain::training::Contract {
25 fn from(record: ContractRecord) -> Self {
26 record.0
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31#[serde(rename_all = "snake_case")]
32pub enum ProgramRecord {
34 StayAndStudy {
36 duration_weeks: StoredProgramDurationWeeks,
38 },
39 TutorSession,
41 GroupClass,
43 PuppyKindergarten,
45 PrivateLesson,
47 AkcCanineGoodCitizenPrep,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
52pub struct StoredProgramDurationWeeks(u8);
54
55impl StoredProgramDurationWeeks {
56 pub const fn try_new(value: u8) -> std::result::Result<Self, StoredProgramDurationWeeksError> {
58 if value == 0 {
59 return Err(StoredProgramDurationWeeksError::ZeroWeeks);
60 }
61 Ok(Self(value))
62 }
63
64 pub const fn get(self) -> u8 {
66 self.0
67 }
68}
69
70impl<'de> Deserialize<'de> for StoredProgramDurationWeeks {
71 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
72 where
73 D: Deserializer<'de>,
74 {
75 Self::try_new(u8::deserialize(deserializer)?).map_err(serde::de::Error::custom)
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
80pub enum StoredProgramDurationWeeksError {
82 #[error("stored training program duration requires at least one week")]
83 ZeroWeeks,
85}
86
87impl TryFrom<program::DurationWeeks> for StoredProgramDurationWeeks {
88 type Error = operations::Error;
89
90 fn try_from(value: program::DurationWeeks) -> operations::Result<Self> {
91 Self::try_new(value.get()).map_err(|err| operations::Error::InvalidDomainValue {
92 field: StorageField::TrainingProgramDurationWeeks,
93 reason: err.to_string(),
94 })
95 }
96}
97
98impl TryFrom<StoredProgramDurationWeeks> for program::DurationWeeks {
99 type Error = operations::Error;
100
101 fn try_from(value: StoredProgramDurationWeeks) -> operations::Result<Self> {
102 program::DurationWeeks::try_new(value.get()).map_err(|err| {
103 operations::Error::InvalidDomainValue {
104 field: StorageField::TrainingProgramDurationWeeks,
105 reason: err.to_string(),
106 }
107 })
108 }
109}
110
111impl TryFrom<domain::training::Program> for ProgramRecord {
112 type Error = operations::Error;
113
114 fn try_from(value: domain::training::Program) -> operations::Result<Self> {
115 Ok(match value {
116 domain::training::Program::StayAndStudy { duration } => Self::StayAndStudy {
117 duration_weeks: duration.try_into()?,
118 },
119 domain::training::Program::TutorSession => Self::TutorSession,
120 domain::training::Program::GroupClass => Self::GroupClass,
121 domain::training::Program::PuppyKindergarten => Self::PuppyKindergarten,
122 domain::training::Program::PrivateLesson => Self::PrivateLesson,
123 domain::training::Program::AkcCanineGoodCitizenPrep => Self::AkcCanineGoodCitizenPrep,
124 })
125 }
126}
127
128impl TryFrom<ProgramRecord> for domain::training::Program {
129 type Error = operations::Error;
130
131 fn try_from(value: ProgramRecord) -> operations::Result<Self> {
132 Ok(match value {
133 ProgramRecord::StayAndStudy { duration_weeks } => Self::StayAndStudy {
134 duration: duration_weeks.try_into()?,
135 },
136 ProgramRecord::TutorSession => Self::TutorSession,
137 ProgramRecord::GroupClass => Self::GroupClass,
138 ProgramRecord::PuppyKindergarten => Self::PuppyKindergarten,
139 ProgramRecord::PrivateLesson => Self::PrivateLesson,
140 ProgramRecord::AkcCanineGoodCitizenPrep => Self::AkcCanineGoodCitizenPrep,
141 })
142 }
143}