spring_batch_rs/item/fake/
person_reader.rs1use std::cell::Cell;
2use std::fmt;
3
4use ::serde::{Deserialize, Serialize, Serializer, ser::Error};
5use fake::faker::internet::raw::*;
6use fake::locales::*;
7use fake::{Fake, faker::name::raw::*};
8use log::debug;
9use rand::RngExt;
10
11use time::format_description;
12use time::{Date, Month};
13
14use crate::core::item::ItemReader;
15use crate::core::item::ItemReaderResult;
16
17#[derive(Serialize, Deserialize, Clone)]
19pub struct Person {
20 first_name: String,
21 last_name: String,
22 title: String,
23 email: String,
24 #[serde(serialize_with = "date_serializer")]
25 birth_date: Date,
26}
27
28fn date_serializer<S>(date: &Date, serializer: S) -> Result<S::Ok, S::Error>
30where
31 S: Serializer,
32{
33 let format = format_description::parse_borrowed::<2>("[year]-[month]-[day]")
34 .map_err(|e| Error::custom(e.to_string()))?;
35 let s = date
36 .format(&format)
37 .map_err(|e| Error::custom(e.to_string()))?;
38 serializer.serialize_str(&s)
39}
40
41impl fmt::Display for Person {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 write!(
44 f,
45 "first_name:{}, last_name:{}, birth_date:{}",
46 self.first_name, self.last_name, self.birth_date
47 )
48 }
49}
50
51pub struct PersonReader {
74 count: Cell<usize>,
75}
76
77impl ItemReader<Person> for PersonReader {
78 fn read(&self) -> ItemReaderResult<Person> {
83 if self.count.get() == 0 {
84 return Ok(None);
85 }
86
87 self.count.set(self.count.get() - 1);
88
89 let person = Person {
90 first_name: FirstName(FR_FR).fake(),
91 last_name: LastName(FR_FR).fake(),
92 title: Title(FR_FR).fake(),
93 email: FreeEmail(FR_FR).fake(),
94 birth_date: fake_date(),
95 };
96 debug!("Person: {}", person);
97 Ok(Some(person))
98 }
99}
100
101fn fake_date() -> Date {
103 let mut rng = rand::rng();
104 let year = rng.random_range(1900..2022);
105 let month = rng.random_range(1..=12);
106 let day = rng.random_range(1..=28);
107
108 Date::from_calendar_date(year, Month::try_from(month).unwrap(), day).unwrap()
109}
110
111#[derive(Default)]
113pub struct PersonReaderBuilder {
114 number_of_items: usize,
115}
116
117impl PersonReaderBuilder {
118 pub fn new() -> Self {
129 Self { number_of_items: 0 }
130 }
131
132 pub fn number_of_items(mut self, number_of_items: usize) -> Self {
143 self.number_of_items = number_of_items;
144 self
145 }
146
147 pub fn build(self) -> PersonReader {
167 PersonReader {
168 count: self.number_of_items.into(),
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::{PersonReader, PersonReaderBuilder};
176 use crate::core::item::ItemReader;
177
178 #[test]
179 fn should_read_configured_number_of_persons() {
180 let reader: PersonReader = PersonReaderBuilder::new().number_of_items(2).build();
181 assert_eq!(reader.count.get(), 2);
182
183 let result1 = reader.read();
184 assert_eq!(reader.count.get(), 1);
185 assert!(result1.is_ok());
186
187 let person = result1.unwrap();
188 assert!(person.is_some());
189 assert!(!person.as_ref().unwrap().first_name.is_empty());
190 assert!(!person.as_ref().unwrap().last_name.is_empty());
191
192 let result2 = reader.read();
193 assert_eq!(reader.count.get(), 0);
194 assert!(result2.is_ok());
195 assert!(result2.unwrap().is_some());
196
197 let result3 = reader.read();
198 assert_eq!(reader.count.get(), 0);
199 assert!(result3.unwrap().is_none());
200 }
201
202 #[test]
203 fn should_display_person_with_all_fields() {
204 let reader = PersonReaderBuilder::new().number_of_items(1).build();
205 let person = reader.read().unwrap().unwrap();
206 let text = format!("{}", person);
207 assert!(
208 text.contains("first_name:"),
209 "Display missing first_name: {text}"
210 );
211 assert!(
212 text.contains("last_name:"),
213 "Display missing last_name: {text}"
214 );
215 assert!(
216 text.contains("birth_date:"),
217 "Display missing birth_date: {text}"
218 );
219 }
220
221 #[test]
222 fn should_serialize_person_with_date_in_iso_format() {
223 let reader = PersonReaderBuilder::new().number_of_items(1).build();
224 let person = reader.read().unwrap().unwrap();
225 let json = serde_json::to_string(&person).expect("serialization must succeed");
226 assert!(
227 json.contains("birth_date"),
228 "missing birth_date key: {json}"
229 );
230 let hyphen_count = json.chars().filter(|&c| c == '-').count();
232 assert!(hyphen_count >= 2, "date should contain hyphens: {json}");
233 }
234}