1use crate::error::{DataFakeError, Result};
2use chrono::Utc;
3use datalogic_rs::{ContextStack, Evaluator, Operator};
4use fake::faker::address::en::{
5 CityName, CountryCode, CountryName, Latitude, Longitude, PostCode, StateAbbr, StateName,
6 StreetName, StreetSuffix, ZipCode,
7};
8use fake::faker::barcode::en::{Isbn10, Isbn13};
9use fake::faker::company::en::{
10 Bs, BsAdj, BsNoun, BsVerb, CatchPhrase, CompanyName, CompanySuffix, Industry, Profession,
11};
12use fake::faker::creditcard::en::CreditCardNumber;
13use fake::faker::currency::en::{CurrencyCode, CurrencyName, CurrencySymbol};
14use fake::faker::filesystem::en::{DirPath, FileExtension, FileName, FilePath};
15use fake::faker::finance::en::Bic;
16use fake::faker::internet::en::{
17 DomainSuffix, FreeEmail, IPv4, IPv6, MACAddress, Password, SafeEmail, UserAgent, Username,
18};
19use fake::faker::lorem::en::{Paragraph, Sentence, Word, Words};
20use fake::faker::name::en::{FirstName, LastName, NameWithTitle, Suffix, Title};
21use fake::faker::phone_number::en::{CellNumber, PhoneNumber};
22use fake::{Fake, Faker};
23use rand::Rng;
24use serde_json::Value;
25
26pub struct FakeOperator;
27
28impl Operator for FakeOperator {
29 fn evaluate(
30 &self,
31 args: &[Value],
32 _context: &mut ContextStack,
33 _evaluator: &dyn Evaluator,
34 ) -> std::result::Result<Value, datalogic_rs::Error> {
35 FakeOperator::generate(args).map_err(|e| datalogic_rs::Error::Custom(e.to_string()))
37 }
38}
39
40impl FakeOperator {
41 pub fn generate(args: &[Value]) -> Result<Value> {
42 if args.is_empty() {
43 return Err(DataFakeError::FakeOperatorError(
44 "Fake operator requires at least one argument".to_string(),
45 ));
46 }
47
48 let method = args[0].as_str().ok_or_else(|| {
49 DataFakeError::FakeOperatorError("First argument must be a string".to_string())
50 })?;
51
52 let _locale = args.get(1).and_then(|v| v.as_str()).unwrap_or("en");
57
58 match method {
59 "u8" => Self::generate_u8(args),
61 "u16" => Self::generate_u16(args),
62 "u32" => Self::generate_u32(args),
63 "u64" => Self::generate_u64(args),
64 "i8" => Self::generate_i8(args),
65 "i16" => Self::generate_i16(args),
66 "i32" => Self::generate_i32(args),
67 "i64" => Self::generate_i64(args),
68 "f32" => Self::generate_f32(args),
69 "f64" => Self::generate_f64(args),
70
71 "bool" | "boolean" => Ok(Value::Bool(rand::rng().random())),
73
74 "uuid" => Ok(Value::String(fake::uuid::UUIDv4.fake())),
76
77 "street_address" => {
79 let street_num: u16 = (1..9999).fake();
81 let street = StreetName().fake::<String>();
82 let suffix = StreetSuffix().fake::<String>();
83 Ok(Value::String(format!("{street_num} {street} {suffix}")))
84 }
85 "city" | "city_name" => Ok(Value::String(CityName().fake())),
86 "country_name" => Ok(Value::String(CountryName().fake())),
87 "country_code" => Ok(Value::String(CountryCode().fake())),
88 "state_name" => Ok(Value::String(StateName().fake())),
89 "state_abbr" => Ok(Value::String(StateAbbr().fake())),
90 "zip_code" | "zip" => Ok(Value::String(ZipCode().fake())),
91 "post_code" | "postcode" | "postal_code" => Ok(Value::String(PostCode().fake())),
92 "latitude" => Ok(Value::Number(
93 serde_json::Number::from_f64(Latitude().fake::<f64>()).unwrap(),
94 )),
95 "longitude" => Ok(Value::Number(
96 serde_json::Number::from_f64(Longitude().fake::<f64>()).unwrap(),
97 )),
98 "street_name" => Ok(Value::String(StreetName().fake())),
99 "street_suffix" => Ok(Value::String(StreetSuffix().fake())),
100
101 "name" | "full_name" => {
103 use fake::faker::name::en::Name;
105 Ok(Value::String(Name().fake()))
106 }
107 "first_name" => Ok(Value::String(FirstName().fake())),
108 "last_name" => Ok(Value::String(LastName().fake())),
109 "name_with_title" => Ok(Value::String(NameWithTitle().fake())),
110 "title" => Ok(Value::String(Title().fake())),
111 "suffix" => Ok(Value::String(Suffix().fake())),
112
113 "company_name" => Ok(Value::String(CompanyName().fake())),
115 "company_suffix" => Ok(Value::String(CompanySuffix().fake())),
116 "industry" => Ok(Value::String(Industry().fake())),
117 "profession" => Ok(Value::String(Profession().fake())),
118 "catch_phrase" => Ok(Value::String(CatchPhrase().fake())),
119 "bs" => Ok(Value::String(Bs().fake())),
120 "bs_adj" => Ok(Value::String(BsAdj().fake())),
121 "bs_noun" => Ok(Value::String(BsNoun().fake())),
122 "bs_verb" => Ok(Value::String(BsVerb().fake())),
123
124 "email" | "safe_email" => Ok(Value::String(SafeEmail().fake())),
126 "free_email" => Ok(Value::String(FreeEmail().fake())),
127 "username" => Ok(Value::String(Username().fake())),
128 "password" => {
129 let min_len = args.get(1).and_then(|v| v.as_u64()).unwrap_or(8) as usize;
130 let max_len = args.get(2).and_then(|v| v.as_u64()).unwrap_or(20) as usize;
131 Ok(Value::String(Password(min_len..max_len).fake()))
132 }
133 "domain_suffix" => Ok(Value::String(DomainSuffix().fake())),
134 "domain_name" => {
135 let words: Vec<String> = Words(1..2).fake();
137 let suffix = DomainSuffix().fake::<String>();
138 Ok(Value::String(format!(
139 "{}.{}",
140 words.join("").to_lowercase(),
141 suffix
142 )))
143 }
144 "ipv4" => Ok(Value::String(IPv4().fake())),
145 "ipv6" => Ok(Value::String(IPv6().fake())),
146 "mac_address" => Ok(Value::String(MACAddress().fake())),
147 "user_agent" => Ok(Value::String(UserAgent().fake())),
148
149 "phone_number" => Ok(Value::String(PhoneNumber().fake())),
151 "cell_number" => Ok(Value::String(CellNumber().fake())),
152
153 "bic" => {
155 let length = args.get(1).and_then(|v| v.as_u64());
157 match length {
158 Some(8) => Self::generate_bic_fixed(8),
159 Some(11) => Self::generate_bic_fixed(11),
160 Some(_) => Err(DataFakeError::FakeOperatorError(
161 "BIC length must be 8 or 11".to_string(),
162 )),
163 None => Ok(Value::String(Bic().fake())), }
165 }
166 "bic8" => Self::generate_bic_fixed(8),
167 "bic11" => Self::generate_bic_fixed(11),
168 "credit_card_number" => Ok(Value::String(CreditCardNumber().fake())),
169
170 "currency_code" => Ok(Value::String(CurrencyCode().fake())),
172 "currency_name" => Ok(Value::String(CurrencyName().fake())),
173 "currency_symbol" => Ok(Value::String(CurrencySymbol().fake())),
174
175 "word" => Ok(Value::String(Word().fake())),
177 "words" => {
178 let count = args.get(1).and_then(|v| v.as_u64()).unwrap_or(5) as usize;
179 let words: Vec<String> = Words(count..count + 1).fake();
180 Ok(Value::String(words.join(" ")))
181 }
182 "sentence" => {
183 let min_words = args.get(1).and_then(|v| v.as_u64()).unwrap_or(4) as usize;
184 let max_words = args.get(2).and_then(|v| v.as_u64()).unwrap_or(10) as usize;
185 Ok(Value::String(Sentence(min_words..max_words).fake()))
186 }
187 "paragraph" => {
188 let min_sentences = args.get(1).and_then(|v| v.as_u64()).unwrap_or(3) as usize;
189 let max_sentences = args.get(2).and_then(|v| v.as_u64()).unwrap_or(7) as usize;
190 Ok(Value::String(
191 Paragraph(min_sentences..max_sentences).fake(),
192 ))
193 }
194
195 "isbn10" => Ok(Value::String(Isbn10().fake())),
197 "isbn13" => Ok(Value::String(Isbn13().fake())),
198
199 "file_name" => Ok(Value::String(FileName().fake())),
201 "file_extension" => Ok(Value::String(FileExtension().fake())),
202 "dir_path" => Ok(Value::String(DirPath().fake())),
203 "file_path" => Ok(Value::String(FilePath().fake())),
204
205 "datetime" | "iso8601_datetime" => {
207 let now = Utc::now();
208 Ok(Value::String(now.to_rfc3339()))
209 }
210 "date" => {
211 let format = args.get(1).and_then(|v| v.as_str()).unwrap_or("%Y-%m-%d");
213 let now = Utc::now();
214 Ok(Value::String(now.format(format).to_string()))
215 }
216 "time" => {
217 let mut rng = rand::rng();
219 let hour = rng.random_range(0..24);
220 let minute = rng.random_range(0..60);
221 let second = rng.random_range(0..60);
222 Ok(Value::String(format!("{hour:02}:{minute:02}:{second:02}")))
223 }
224 "month_name" => {
225 let months = [
227 "January",
228 "February",
229 "March",
230 "April",
231 "May",
232 "June",
233 "July",
234 "August",
235 "September",
236 "October",
237 "November",
238 "December",
239 ];
240 let mut rng = rand::rng();
241 let idx = rng.random_range(0..months.len());
242 Ok(Value::String(months[idx].to_string()))
243 }
244
245 "iban" => {
247 let country = args.get(1).and_then(|v| v.as_str()).unwrap_or("DE");
248 let mut rng = rand::rng();
249 let check = format!("{:02}", rng.random_range(10..99));
250 let account: String = (0..18)
251 .map(|_| rng.random_range(0..10).to_string())
252 .collect();
253 Ok(Value::String(format!("{country}{check}{account}")))
254 }
255 "lei" => {
256 let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
258 let mut rng = rand::rng();
259 let lei: String = (0..18)
260 .map(|_| chars.chars().nth(rng.random_range(0..chars.len())).unwrap())
261 .collect();
262 let check = format!("{:02}", rng.random_range(10..99));
263 Ok(Value::String(format!("{lei}{check}")))
264 }
265 "alphanumeric" => {
266 let min_len = args.get(1).and_then(|v| v.as_u64()).unwrap_or(10) as usize;
267 let max_len = args
268 .get(2)
269 .and_then(|v| v.as_u64())
270 .unwrap_or(min_len as u64) as usize;
271 let mut rng = rand::rng();
272 let len = if min_len == max_len {
273 min_len
274 } else {
275 rng.random_range(min_len..=max_len)
276 };
277 let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
278 let result: String = (0..len)
279 .map(|_| chars.chars().nth(rng.random_range(0..chars.len())).unwrap())
280 .collect();
281 Ok(Value::String(result))
282 }
283
284 "enum" | "pick" | "choice" => {
286 if args.len() < 2 {
287 return Err(DataFakeError::FakeOperatorError(
288 "enum requires at least one option".to_string(),
289 ));
290 }
291 let options = &args[1..];
292 let mut rng = rand::rng();
293 let idx = rng.random_range(0..options.len());
294 Ok(options[idx].clone())
295 }
296
297 "regex" => {
307 if let Some(Value::String(pattern)) = args.get(1) {
308 if pattern.starts_with('(') && pattern.ends_with(')') {
310 let inner = &pattern[1..pattern.len() - 1];
311 let options: Vec<&str> = inner.split('|').collect();
312 if !options.is_empty() {
313 let mut rng = rand::rng();
314 let idx = rng.random_range(0..options.len());
315 return Ok(Value::String(options[idx].to_string()));
316 }
317 }
318 Ok(Value::String("REGEX_PATTERN".to_string()))
320 } else {
321 Err(DataFakeError::FakeOperatorError(
322 "regex requires a pattern argument".to_string(),
323 ))
324 }
325 }
326
327 _ => Err(DataFakeError::FakeOperatorError(format!(
328 "Unknown fake method: {method}"
329 ))),
330 }
331 }
332}
333
334macro_rules! impl_integer_generator {
337 ($fn_name:ident, $type:ty, $extract_fn:ident, $default_min:expr, $default_max:expr) => {
338 fn $fn_name(args: &[Value]) -> Result<Value> {
339 match args.len() {
340 1 => Ok(Value::Number(serde_json::Number::from(
341 Faker.fake::<$type>(),
342 ))),
343 3 => {
344 let min = args[1].$extract_fn().unwrap_or($default_min as _) as $type;
345 let max = args[2].$extract_fn().unwrap_or($default_max as _) as $type;
346 Ok(Value::Number(serde_json::Number::from(
347 rand::rng().random_range(min..=max),
348 )))
349 }
350 _ => Err(DataFakeError::FakeOperatorError(
351 concat!(stringify!($type), " requires either 1 or 3 arguments").to_string(),
352 )),
353 }
354 }
355 };
356}
357
358macro_rules! impl_float_generator {
360 ($fn_name:ident, $type:ty) => {
361 fn $fn_name(args: &[Value]) -> Result<Value> {
362 match args.len() {
363 1 => Ok(Value::Number(
364 serde_json::Number::from_f64(Faker.fake::<$type>() as f64)
365 .expect("Generated float should be a valid JSON number"),
366 )),
367 3 => {
368 let min = args[1].as_f64().unwrap_or(0.0) as $type;
369 let max = args[2].as_f64().unwrap_or(1.0) as $type;
370 let value = rand::rng().random_range(min..=max);
371 Ok(Value::Number(
372 serde_json::Number::from_f64(value as f64)
373 .expect("Generated float should be a valid JSON number"),
374 ))
375 }
376 _ => Err(DataFakeError::FakeOperatorError(
377 concat!(stringify!($type), " requires either 1 or 3 arguments").to_string(),
378 )),
379 }
380 }
381 };
382}
383
384impl FakeOperator {
385 impl_integer_generator!(generate_u8, u8, as_u64, 0, u8::MAX);
387 impl_integer_generator!(generate_u16, u16, as_u64, 0, u16::MAX);
388 impl_integer_generator!(generate_u32, u32, as_u64, 0, u32::MAX);
389 impl_integer_generator!(generate_u64, u64, as_u64, 0, u64::MAX);
390 impl_integer_generator!(generate_i8, i8, as_i64, i8::MIN, i8::MAX);
391 impl_integer_generator!(generate_i16, i16, as_i64, i16::MIN, i16::MAX);
392 impl_integer_generator!(generate_i32, i32, as_i64, i32::MIN, i32::MAX);
393 impl_integer_generator!(generate_i64, i64, as_i64, i64::MIN, i64::MAX);
394
395 impl_float_generator!(generate_f32, f32);
397 impl_float_generator!(generate_f64, f64);
398
399 fn generate_bic_fixed(length: u64) -> Result<Value> {
400 use rand::seq::IndexedRandom;
401 let mut rng = rand::rng();
402
403 const ALPHABET: &[char; 26] = &[
405 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
406 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
407 ];
408 const VOWELS: &[char; 5] = &['A', 'E', 'I', 'O', 'U'];
409 const ISO3166: &[&str] = &[
410 "AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT",
411 "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL",
412 "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BY", "BZ", "CA", "CC",
413 "CD", "CE", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CP", "CR", "CS",
414 "CU", "CV", "CW", "CX", "CY", "CZ", "DD", "DE", "DG", "DJ", "DK", "DM", "DO", "DZ",
415 "EA", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "EU", "FI", "FJ", "FK", "FM", "FO",
416 "FR", "FX", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP",
417 "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "IC",
418 "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP",
419 "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC",
420 "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG",
421 "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW",
422 "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NT",
423 "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS",
424 "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE",
425 "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SU", "SV",
426 "SX", "SY", "SZ", "TA", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN",
427 "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC",
428 "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW",
429 ];
430
431 let base_bic = format!(
433 "{}{}{}{}{}{}1",
434 *ALPHABET.choose(&mut rng).unwrap(),
435 *ALPHABET.choose(&mut rng).unwrap(),
436 *ALPHABET.choose(&mut rng).unwrap(),
437 *VOWELS.choose(&mut rng).unwrap(),
438 *ISO3166.choose(&mut rng).unwrap(),
439 *ALPHABET.choose(&mut rng).unwrap(),
440 );
441
442 let bic = if length == 11 {
443 let prob: i8 = rng.random_range(0..100);
445 let suffix = if prob < 70 {
446 format!(
448 "{}{}{}",
449 rng.random_range('0'..='9'),
450 rng.random_range('0'..='9'),
451 rng.random_range('0'..='9'),
452 )
453 } else {
454 format!(
456 "{}{}{}",
457 *ALPHABET.choose(&mut rng).unwrap(),
458 *VOWELS.choose(&mut rng).unwrap(),
459 *ALPHABET.choose(&mut rng).unwrap(),
460 )
461 };
462 format!("{}{}", base_bic, suffix)
463 } else {
464 base_bic
465 };
466
467 Ok(Value::String(bic))
468 }
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474 use serde_json::json;
475
476 #[test]
477 fn test_generate_uuid() {
478 let args = vec![json!("uuid")];
479 let result = FakeOperator::generate(&args).unwrap();
480 assert!(result.is_string());
481 assert_eq!(result.as_str().unwrap().len(), 36); }
483
484 #[test]
485 fn test_generate_numeric_no_range() {
486 let args = vec![json!("u8")];
487 let result = FakeOperator::generate(&args).unwrap();
488 assert!(result.is_number());
489 }
490
491 #[test]
492 fn test_generate_numeric_with_range() {
493 let args = vec![json!("u8"), json!(10), json!(20)];
494 let result = FakeOperator::generate(&args).unwrap();
495 assert!(result.is_number());
496 let value = result.as_u64().unwrap();
497 assert!((10..=20).contains(&value));
498 }
499
500 #[test]
501 fn test_generate_name_with_locale() {
502 let args = vec![json!("name"), json!("en_US")];
503 let result = FakeOperator::generate(&args).unwrap();
504 assert!(result.is_string());
505 assert!(!result.as_str().unwrap().is_empty());
506 }
507
508 #[test]
509 fn test_generate_email() {
510 let args = vec![json!("email")];
511 let result = FakeOperator::generate(&args).unwrap();
512 assert!(result.is_string());
513 let email = result.as_str().unwrap();
514 assert!(email.contains('@'));
515 }
516
517 #[test]
518 fn test_generate_password_with_length() {
519 let args = vec![json!("password"), json!(10), json!(15)];
520 let result = FakeOperator::generate(&args).unwrap();
521 assert!(result.is_string());
522 let password = result.as_str().unwrap();
523 assert!(password.len() >= 10 && password.len() <= 15);
524 }
525
526 #[test]
527 fn test_invalid_method() {
528 let args = vec![json!("invalid_method")];
529 let result = FakeOperator::generate(&args);
530 assert!(result.is_err());
531 }
532
533 #[test]
534 fn test_empty_args() {
535 let args = vec![];
536 let result = FakeOperator::generate(&args);
537 assert!(result.is_err());
538 }
539
540 #[test]
541 fn test_generate_bic_default() {
542 let args = vec![json!("bic")];
543 let result = FakeOperator::generate(&args).unwrap();
544 assert!(result.is_string());
545 let bic = result.as_str().unwrap();
546 assert!(bic.len() == 8 || bic.len() == 11);
547 }
548
549 #[test]
550 fn test_generate_bic8() {
551 let args = vec![json!("bic8")];
552 let result = FakeOperator::generate(&args).unwrap();
553 assert!(result.is_string());
554 let bic = result.as_str().unwrap();
555 assert_eq!(bic.len(), 8);
556 }
557
558 #[test]
559 fn test_generate_bic11() {
560 let args = vec![json!("bic11")];
561 let result = FakeOperator::generate(&args).unwrap();
562 assert!(result.is_string());
563 let bic = result.as_str().unwrap();
564 assert_eq!(bic.len(), 11);
565 }
566
567 #[test]
568 fn test_generate_bic_with_length_8() {
569 let args = vec![json!("bic"), json!(8)];
570 let result = FakeOperator::generate(&args).unwrap();
571 assert!(result.is_string());
572 let bic = result.as_str().unwrap();
573 assert_eq!(bic.len(), 8);
574 }
575
576 #[test]
577 fn test_generate_bic_with_length_11() {
578 let args = vec![json!("bic"), json!(11)];
579 let result = FakeOperator::generate(&args).unwrap();
580 assert!(result.is_string());
581 let bic = result.as_str().unwrap();
582 assert_eq!(bic.len(), 11);
583 }
584
585 #[test]
586 fn test_generate_bic_with_invalid_length() {
587 let args = vec![json!("bic"), json!(10)];
588 let result = FakeOperator::generate(&args);
589 assert!(result.is_err());
590 match result {
591 Err(DataFakeError::FakeOperatorError(msg)) => {
592 assert!(msg.contains("BIC length must be 8 or 11"));
593 }
594 _ => panic!("Expected FakeOperatorError with specific message"),
595 }
596 }
597}