rws_server/test_client/
factory.rs1use std::any::TypeId;
40use std::collections::HashMap;
41use std::marker::PhantomData;
42use std::sync::{Mutex, OnceLock};
43
44use crate::model::repository::insert_entity;
45use crate::model::{DbError, DbPool, Model};
46
47pub trait Factory: Model + Sized {
49 fn factory_default(seq: u64) -> Self;
52}
53
54pub trait FactoryValue: Sized {
56 fn factory_value(field: &str, seq: u64) -> Self;
58
59 fn factory_key(field: &str, seq: u64) -> Self {
62 Self::factory_value(field, seq)
63 }
64}
65
66macro_rules! numbers {
67 ($($t:ty),*) => {$(
68 impl FactoryValue for $t {
69 fn factory_value(_field: &str, _seq: u64) -> Self {
70 0 as $t
71 }
72 fn factory_key(_field: &str, seq: u64) -> Self {
73 seq as $t
74 }
75 }
76 )*};
77}
78numbers!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
79
80impl FactoryValue for bool {
81 fn factory_value(_field: &str, _seq: u64) -> Self {
82 false
83 }
84}
85
86impl FactoryValue for String {
87 fn factory_value(field: &str, seq: u64) -> Self {
88 if field.to_ascii_lowercase().contains("email") {
89 format!("{field}-{seq}@example.com")
90 } else {
91 format!("{field}-{seq}")
92 }
93 }
94}
95
96impl<T> FactoryValue for Option<T> {
97 fn factory_value(_field: &str, _seq: u64) -> Self {
98 None
99 }
100}
101
102impl FactoryValue for Vec<u8> {
103 fn factory_value(_field: &str, _seq: u64) -> Self {
104 Vec::new()
105 }
106}
107
108fn next_seq<T: 'static>() -> u64 {
110 static SEQUENCES: OnceLock<Mutex<HashMap<TypeId, u64>>> = OnceLock::new();
111 let mut sequences = SEQUENCES.get_or_init(Default::default).lock().unwrap_or_else(|e| e.into_inner());
112 let seq = sequences.entry(TypeId::of::<T>()).or_insert(0);
113 *seq += 1;
114 *seq
115}
116
117type Override<T> = Box<dyn Fn(&mut T) + Send + Sync>;
118
119pub struct ModelFactory<T> {
121 overrides: Vec<Override<T>>,
122 _model: PhantomData<fn() -> T>,
123}
124
125impl<T: Factory + 'static> Default for ModelFactory<T> {
126 fn default() -> Self {
127 ModelFactory::new()
128 }
129}
130
131impl<T: Factory + 'static> ModelFactory<T> {
132 pub fn new() -> Self {
134 ModelFactory { overrides: Vec::new(), _model: PhantomData }
135 }
136
137 pub fn with(mut self, f: impl Fn(&mut T) + Send + Sync + 'static) -> Self {
140 self.overrides.push(Box::new(f));
141 self
142 }
143
144 pub fn build(&self) -> T {
146 let mut model = T::factory_default(next_seq::<T>());
147 for f in &self.overrides {
148 f(&mut model);
149 }
150 model
151 }
152
153 pub fn build_many(&self, n: usize) -> Vec<T> {
155 (0..n).map(|_| self.build()).collect()
156 }
157
158 pub async fn create(&self, pool: &DbPool) -> Result<T, DbError> {
161 insert_entity(pool, &self.build()).await
162 }
163
164 pub async fn create_many(&self, n: usize, pool: &DbPool) -> Result<Vec<T>, DbError> {
166 let mut created = Vec::with_capacity(n);
167 for _ in 0..n {
168 created.push(self.create(pool).await?);
169 }
170 Ok(created)
171 }
172}
173
174#[doc(hidden)]
176pub mod __private {
177 use super::FactoryValue;
178 use std::marker::PhantomData;
179
180 pub struct Probe<T>(pub PhantomData<T>);
183
184 pub trait ViaValue<T> {
185 fn make(&self, field: &str, seq: u64) -> T;
186 fn make_key(&self, field: &str, seq: u64) -> T;
187 }
188
189 impl<T: FactoryValue> ViaValue<T> for &Probe<T> {
190 fn make(&self, field: &str, seq: u64) -> T {
191 T::factory_value(field, seq)
192 }
193 fn make_key(&self, field: &str, seq: u64) -> T {
194 T::factory_key(field, seq)
195 }
196 }
197
198 pub trait ViaDefault<T> {
199 fn make(&self, field: &str, seq: u64) -> T;
200 fn make_key(&self, field: &str, seq: u64) -> T;
201 }
202
203 impl<T: Default> ViaDefault<T> for Probe<T> {
204 fn make(&self, _field: &str, _seq: u64) -> T {
205 T::default()
206 }
207 fn make_key(&self, _field: &str, _seq: u64) -> T {
208 T::default()
209 }
210 }
211}