1use super::{FieldDef, FieldGenerator, FieldType, ModelDef, Record};
6use rand::rngs::StdRng;
7use rand::Rng;
8use rand::SeedableRng;
9use serde_json::{json, Value};
10use std::collections::HashMap;
11
12pub struct FakerGenerator {
14 field_generators: HashMap<String, Box<dyn FieldGenerator>>,
15 rng: StdRng,
16}
17
18impl FakerGenerator {
19 pub fn new() -> Self {
21 let mut gen = Self {
22 field_generators: HashMap::new(),
23 rng: StdRng::from_entropy(),
24 };
25 gen.register_defaults();
26 gen
27 }
28
29 pub fn with_seed(seed: u64) -> Self {
31 let mut gen = Self {
32 field_generators: HashMap::new(),
33 rng: StdRng::seed_from_u64(seed),
34 };
35 gen.register_defaults();
36 gen
37 }
38
39 fn register_defaults(&mut self) {
40 self.register("name", Box::new(NameGenerator));
41 self.register("email", Box::new(EmailGenerator));
42 self.register("address", Box::new(AddressGenerator));
43 self.register("phone", Box::new(PhoneGenerator));
44 self.register("uuid", Box::new(UuidGenerator));
45 self.register("date", Box::new(DateGenerator));
46 self.register("boolean", Box::new(BooleanGenerator));
47 }
48
49 pub fn register(&mut self, semantic: &str, generator: Box<dyn FieldGenerator>) {
51 self.field_generators
52 .insert(semantic.to_string(), generator);
53 }
54
55 pub fn infer_generator(field_type: &FieldType) -> Box<dyn FieldGenerator> {
57 match field_type {
58 FieldType::String => Box::new(NameGenerator),
59 FieldType::I32 | FieldType::U32 => Box::new(NumberGenerator::new(1, 100)),
60 FieldType::I64 | FieldType::U64 => Box::new(NumberGenerator::new(1, 10000)),
61 FieldType::F64 => Box::new(FloatGenerator::new(0.0, 100.0)),
62 FieldType::Boolean => Box::new(BooleanGenerator),
63 FieldType::Uuid => Box::new(UuidGenerator),
64 FieldType::DateTime => Box::new(DateGenerator),
65 FieldType::Json => Box::new(JsonGenerator),
66 FieldType::Enum(variants) => Box::new(EnumGenerator::new(variants.clone())),
67 }
68 }
69
70 pub fn generate_batch(&mut self, model: &ModelDef, count: usize) -> Vec<Record> {
72 let mut records = Vec::with_capacity(count);
73 for _ in 0..count {
74 let mut record = serde_json::Map::new();
75 for field in &model.fields {
76 let value = self.generate_field(field);
77 record.insert(field.name.clone(), value);
78 }
79 records.push(record);
80 }
81 records
82 }
83
84 fn generate_field(&mut self, field: &FieldDef) -> Value {
85 if field.nullable && self.rng.gen_bool(0.1) {
86 return Value::Null;
87 }
88 let semantic_key = format!("{}.{}", "", field.name);
89 if let Some(gen) = self.field_generators.get(&field.name) {
90 return gen.generate(&mut self.rng);
91 }
92 if let Some(gen) = self.field_generators.get(&semantic_key) {
93 return gen.generate(&mut self.rng);
94 }
95 let gen = Self::infer_generator(&field.field_type);
96 gen.generate(&mut self.rng)
97 }
98}
99
100impl Default for FakerGenerator {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106pub struct NameGenerator;
110impl FieldGenerator for NameGenerator {
111 fn generate(&self, rng: &mut StdRng) -> Value {
112 const NAMES: &[&str] = &[
113 "张伟", "王芳", "李娜", "刘洋", "陈静", "杨磊", "赵敏", "黄强", "周丽", "吴杰", "徐涛",
114 "孙艳", "马超", "朱琳", "胡军", "郭雪", "何明", "高飞", "林秀", "罗刚",
115 ];
116 Value::String(NAMES[rng.gen_range(0..NAMES.len())].to_string())
117 }
118}
119
120pub struct EmailGenerator;
122impl FieldGenerator for EmailGenerator {
123 fn generate(&self, rng: &mut StdRng) -> Value {
124 const DOMAINS: &[&str] = &[
125 "gmail.com",
126 "qq.com",
127 "163.com",
128 "outlook.com",
129 "huawei.com",
130 ];
131 let id: u64 = rng.gen_range(1000..99999);
132 let domain = DOMAINS[rng.gen_range(0..DOMAINS.len())];
133 Value::String(format!("user{}@{}", id, domain))
134 }
135}
136
137pub struct AddressGenerator;
139impl FieldGenerator for AddressGenerator {
140 fn generate(&self, rng: &mut StdRng) -> Value {
141 const CITIES: &[&str] = &[
142 "北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "西安",
143 ];
144 let city = CITIES[rng.gen_range(0..CITIES.len())];
145 let street: u32 = rng.gen_range(1..999);
146 Value::String(format!("{}市XX路{}号", city, street))
147 }
148}
149
150pub struct PhoneGenerator;
152impl FieldGenerator for PhoneGenerator {
153 fn generate(&self, rng: &mut StdRng) -> Value {
154 let prefix: u32 = rng.gen_range(130..190);
155 let suffix: u64 = rng.gen_range(10000000..99999999);
156 Value::String(format!("{}{:08}", prefix, suffix))
157 }
158}
159
160pub struct UuidGenerator;
162impl FieldGenerator for UuidGenerator {
163 fn generate(&self, rng: &mut StdRng) -> Value {
164 let bytes: [u8; 16] = rng.gen();
165 format!(
166 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
167 bytes[0], bytes[1], bytes[2], bytes[3],
168 bytes[4], bytes[5], bytes[6], bytes[7],
169 bytes[8], bytes[9], bytes[10], bytes[11],
170 bytes[12], bytes[13], bytes[14], bytes[15]
171 )
172 .into()
173 }
174}
175
176pub struct DateGenerator;
178impl FieldGenerator for DateGenerator {
179 fn generate(&self, rng: &mut StdRng) -> Value {
180 let year: u32 = rng.gen_range(1970..2100);
181 let month: u32 = rng.gen_range(1..13);
182 let day: u32 = rng.gen_range(1..29);
183 Value::String(format!("{:04}-{:02}-{:02}", year, month, day))
184 }
185}
186
187pub struct NumberGenerator {
189 min: i64,
190 max: i64,
191}
192impl NumberGenerator {
193 pub fn new(min: i64, max: i64) -> Self {
195 Self { min, max }
196 }
197}
198impl FieldGenerator for NumberGenerator {
199 fn generate(&self, rng: &mut StdRng) -> Value {
200 json!(rng.gen_range(self.min..self.max))
201 }
202}
203
204pub struct FloatGenerator {
206 min: f64,
207 max: f64,
208}
209impl FloatGenerator {
210 pub fn new(min: f64, max: f64) -> Self {
212 Self { min, max }
213 }
214}
215impl FieldGenerator for FloatGenerator {
216 fn generate(&self, rng: &mut StdRng) -> Value {
217 let val = rng.gen_range(self.min..self.max);
218 json!(val)
219 }
220}
221
222pub struct BooleanGenerator;
224impl FieldGenerator for BooleanGenerator {
225 fn generate(&self, rng: &mut StdRng) -> Value {
226 Value::Bool(rng.gen_bool(0.5))
227 }
228}
229
230pub struct EnumGenerator {
232 variants: Vec<String>,
233}
234impl EnumGenerator {
235 pub fn new(variants: Vec<String>) -> Self {
237 Self { variants }
238 }
239}
240impl FieldGenerator for EnumGenerator {
241 fn generate(&self, rng: &mut StdRng) -> Value {
242 if self.variants.is_empty() {
243 return Value::Null;
244 }
245 Value::String(self.variants[rng.gen_range(0..self.variants.len())].clone())
246 }
247}
248
249pub struct JsonGenerator;
251impl FieldGenerator for JsonGenerator {
252 fn generate(&self, rng: &mut StdRng) -> Value {
253 json!({
254 "id": rng.gen::<u32>(),
255 "active": rng.gen_bool(0.5),
256 })
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263 use crate::seeding::FieldDef;
264
265 fn user_model() -> ModelDef {
266 ModelDef {
267 table: "users".to_string(),
268 fields: vec![
269 FieldDef {
270 name: "name".to_string(),
271 field_type: FieldType::String,
272 nullable: false,
273 },
274 FieldDef {
275 name: "email".to_string(),
276 field_type: FieldType::String,
277 nullable: false,
278 },
279 FieldDef {
280 name: "age".to_string(),
281 field_type: FieldType::U32,
282 nullable: false,
283 },
284 ],
285 }
286 }
287
288 #[test]
289 fn test_generate_batch_basic() {
290 let mut faker = FakerGenerator::with_seed(42);
291 let model = user_model();
292 let records = faker.generate_batch(&model, 10);
293 assert_eq!(records.len(), 10);
294 for record in &records {
295 assert!(record.contains_key("name"));
296 assert!(record.contains_key("email"));
297 assert!(record.contains_key("age"));
298 let name = record["name"].as_str().unwrap();
299 assert!(!name.is_empty());
300 }
301 }
302
303 #[test]
304 fn test_email_generator_format() {
305 let mut faker = FakerGenerator::with_seed(42);
306 let model = ModelDef {
307 table: "test".to_string(),
308 fields: vec![FieldDef {
309 name: "email".to_string(),
310 field_type: FieldType::String,
311 nullable: false,
312 }],
313 };
314 let records = faker.generate_batch(&model, 5);
315 for record in &records {
316 let email = record["email"].as_str().unwrap();
317 assert!(email.contains('@'));
318 }
319 }
320
321 #[test]
322 fn test_register_custom_generator() {
323 let mut faker = FakerGenerator::with_seed(42);
324 faker.register("custom_field", Box::new(NameGenerator));
325 let model = ModelDef {
326 table: "test".to_string(),
327 fields: vec![FieldDef {
328 name: "custom_field".to_string(),
329 field_type: FieldType::String,
330 nullable: false,
331 }],
332 };
333 let records = faker.generate_batch(&model, 3);
334 assert_eq!(records.len(), 3);
335 for record in &records {
336 assert!(record["custom_field"].is_string());
337 }
338 }
339
340 #[test]
341 fn test_nullable_field() {
342 let mut faker = FakerGenerator::with_seed(42);
343 let model = ModelDef {
344 table: "test".to_string(),
345 fields: vec![FieldDef {
346 name: "opt".to_string(),
347 field_type: FieldType::String,
348 nullable: true,
349 }],
350 };
351 let records = faker.generate_batch(&model, 100);
352 let null_count = records.iter().filter(|r| r["opt"].is_null()).count();
353 assert!(null_count > 0, "nullable field should produce some nulls");
354 }
355
356 #[test]
357 fn test_uuid_generator_format() {
358 let mut rng = StdRng::seed_from_u64(42);
359 let val = UuidGenerator.generate(&mut rng);
360 let uuid_str = val.as_str().unwrap();
361 assert_eq!(uuid_str.len(), 36);
362 assert_eq!(uuid_str.chars().nth(8), Some('-'));
363 assert_eq!(uuid_str.chars().nth(13), Some('-'));
364 assert_eq!(uuid_str.chars().nth(18), Some('-'));
365 assert_eq!(uuid_str.chars().nth(23), Some('-'));
366 }
367
368 #[test]
369 fn test_enum_generator() {
370 let mut rng = StdRng::seed_from_u64(42);
371 let gen = EnumGenerator::new(vec!["active".into(), "inactive".into(), "banned".into()]);
372 let val = gen.generate(&mut rng);
373 let s = val.as_str().unwrap();
374 assert!(["active", "inactive", "banned"].contains(&s));
375 }
376
377 #[test]
378 fn test_infer_generator() {
379 let gen = FakerGenerator::infer_generator(&FieldType::Boolean);
380 let mut rng = StdRng::seed_from_u64(42);
381 let val = gen.generate(&mut rng);
382 assert!(val.is_boolean());
383 }
384}