1use async_graphql::Value;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
9pub struct MockResolver {
10    pub field_name: String,
11    pub field_type: String,
12    pub mock_data: Value,
13    pub generator: Option<MockDataGenerator>,
14}
15
16#[derive(Debug, Clone)]
18pub struct MockDataGenerator {
19    pub generator_type: GeneratorType,
20    pub config: HashMap<String, serde_json::Value>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(tag = "type")]
26pub enum GeneratorType {
27    String {
29        min_length: usize,
30        max_length: usize,
31    },
32    Int { min: i64, max: i64 },
34    Float { min: f64, max: f64 },
36    Uuid,
38    Email,
40    Name,
42    Timestamp,
44    FromList { values: Vec<serde_json::Value> },
46    Object {
48        fields: HashMap<String, Box<GeneratorType>>,
49    },
50    Array {
52        item_generator: Box<GeneratorType>,
53        min_items: usize,
54        max_items: usize,
55    },
56}
57
58pub struct ResolverRegistry {
60    resolvers: HashMap<String, HashMap<String, MockResolver>>,
61}
62
63impl ResolverRegistry {
64    pub fn new() -> Self {
66        Self {
67            resolvers: HashMap::new(),
68        }
69    }
70
71    pub fn register_resolver(&mut self, type_name: &str, resolver: MockResolver) {
73        self.resolvers
74            .entry(type_name.to_string())
75            .or_insert_with(HashMap::new)
76            .insert(resolver.field_name.clone(), resolver);
77    }
78
79    pub fn get_resolver(&self, type_name: &str, field_name: &str) -> Option<&MockResolver> {
81        self.resolvers
82            .get(type_name)
83            .and_then(|type_resolvers| type_resolvers.get(field_name))
84    }
85
86    pub async fn generate_mock_data(&self, type_name: &str, field_name: &str) -> Value {
88        if let Some(resolver) = self.get_resolver(type_name, field_name) {
89            if let Some(generator) = &resolver.generator {
90                return generator.generate().await;
91            }
92            return resolver.mock_data.clone();
93        }
94
95        Self::generate_default_mock_data(field_name).await
97    }
98
99    async fn generate_default_mock_data(field_name: &str) -> Value {
101        match field_name.to_lowercase().as_str() {
102            "id" => Value::String(mockforge_core::templating::expand_str("{{uuid}}")),
103            "name" | "title" => {
104                Value::String(mockforge_core::templating::expand_str("{{faker.name}}"))
105            }
106            "email" => Value::String(mockforge_core::templating::expand_str("{{faker.email}}")),
107            "description" | "content" => {
108                Value::String(mockforge_core::templating::expand_str("{{faker.sentence}}"))
109            }
110            "age" | "count" | "quantity" => Value::Number((rand::random::<u32>() % 100).into()),
111            "price" | "amount" => {
112                let val = rand::random::<f64>() * 1000.0;
113                Value::Number(
114                    serde_json::Number::from_f64(val)
115                        .unwrap_or_else(|| serde_json::Number::from(0)),
116                )
117            }
118            "active" | "enabled" | "is_active" => Value::Boolean(rand::random::<bool>()),
119            "created_at" | "updated_at" => {
120                Value::String(mockforge_core::templating::expand_str("{{now}}"))
121            }
122            _ => Value::String(mockforge_core::templating::expand_str(&format!(
123                "{{{{faker.word}}}}"
124            ))),
125        }
126    }
127
128    pub fn create_common_resolvers() -> Self {
130        let mut registry = Self::new();
131
132        registry.register_resolver(
134            "User",
135            MockResolver {
136                field_name: "id".to_string(),
137                field_type: "ID!".to_string(),
138                mock_data: Value::Null,
139                generator: Some(MockDataGenerator {
140                    generator_type: GeneratorType::Uuid,
141                    config: HashMap::new(),
142                }),
143            },
144        );
145
146        registry.register_resolver(
147            "User",
148            MockResolver {
149                field_name: "name".to_string(),
150                field_type: "String!".to_string(),
151                mock_data: Value::Null,
152                generator: Some(MockDataGenerator {
153                    generator_type: GeneratorType::Name,
154                    config: HashMap::new(),
155                }),
156            },
157        );
158
159        registry.register_resolver(
160            "User",
161            MockResolver {
162                field_name: "email".to_string(),
163                field_type: "String!".to_string(),
164                mock_data: Value::Null,
165                generator: Some(MockDataGenerator {
166                    generator_type: GeneratorType::Email,
167                    config: HashMap::new(),
168                }),
169            },
170        );
171
172        registry.register_resolver(
173            "User",
174            MockResolver {
175                field_name: "createdAt".to_string(),
176                field_type: "String!".to_string(),
177                mock_data: Value::Null,
178                generator: Some(MockDataGenerator {
179                    generator_type: GeneratorType::Timestamp,
180                    config: HashMap::new(),
181                }),
182            },
183        );
184
185        registry
186    }
187}
188
189impl MockDataGenerator {
190    pub async fn generate(&self) -> Value {
192        match &self.generator_type {
193            GeneratorType::String {
194                min_length,
195                max_length,
196            } => {
197                use rand::Rng;
198                let mut rng = rand::thread_rng();
199                let length = rng.gen_range(*min_length..*max_length);
200                let s: String = (0..length)
201                    .map(|_| {
202                        let c = rng.gen_range(b'a'..=b'z');
203                        c as char
204                    })
205                    .collect();
206                Value::String(s)
207            }
208            GeneratorType::Int { min, max } => {
209                let num = rand::random::<i64>() % (max - min) + min;
210                Value::Number(num.into())
211            }
212            GeneratorType::Float { min, max } => {
213                let num = rand::random::<f64>() * (max - min) + min;
214                Value::Number(
215                    serde_json::Number::from_f64(num)
216                        .unwrap_or_else(|| serde_json::Number::from(0)),
217                )
218            }
219            GeneratorType::Uuid => {
220                Value::String(mockforge_core::templating::expand_str("{{uuid}}"))
221            }
222            GeneratorType::Email => {
223                Value::String(mockforge_core::templating::expand_str("{{faker.email}}"))
224            }
225            GeneratorType::Name => {
226                Value::String(mockforge_core::templating::expand_str("{{faker.name}}"))
227            }
228            GeneratorType::Timestamp => {
229                Value::String(mockforge_core::templating::expand_str("{{now}}"))
230            }
231            GeneratorType::FromList { values } => {
232                use rand::Rng;
233                if values.is_empty() {
234                    Value::Null
235                } else {
236                    let mut rng = rand::thread_rng();
237                    let index = rng.gen_range(0..values.len());
238                    serde_json::from_value(values[index].clone()).unwrap_or(Value::Null)
239                }
240            }
241            GeneratorType::Object { fields: _ } => {
242                use indexmap::IndexMap;
248                let map = IndexMap::new();
249                Value::Object(map)
250            }
251            GeneratorType::Array {
252                item_generator: _,
253                min_items,
254                max_items,
255            } => {
256                use rand::Rng;
262                let mut rng = rand::thread_rng();
263                let count = rng.gen_range(*min_items..*max_items);
264                let items = vec![Value::Null; count];
265                Value::List(items)
266            }
267        }
268    }
269}
270
271impl Default for ResolverRegistry {
272    fn default() -> Self {
273        Self::new()
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use super::*;
280
281    #[test]
282    fn test_mock_resolver_creation() {
283        let resolver = MockResolver {
284            field_name: "id".to_string(),
285            field_type: "ID!".to_string(),
286            mock_data: Value::String("test-123".to_string()),
287            generator: None,
288        };
289
290        assert_eq!(resolver.field_name, "id");
291        assert_eq!(resolver.field_type, "ID!");
292        assert!(resolver.generator.is_none());
293    }
294
295    #[test]
296    fn test_mock_resolver_with_generator() {
297        let resolver = MockResolver {
298            field_name: "email".to_string(),
299            field_type: "String!".to_string(),
300            mock_data: Value::Null,
301            generator: Some(MockDataGenerator {
302                generator_type: GeneratorType::Email,
303                config: HashMap::new(),
304            }),
305        };
306
307        assert!(resolver.generator.is_some());
308    }
309
310    #[test]
311    fn test_generator_type_string() {
312        let gen_type = GeneratorType::String {
313            min_length: 5,
314            max_length: 10,
315        };
316
317        match gen_type {
318            GeneratorType::String {
319                min_length,
320                max_length,
321            } => {
322                assert_eq!(min_length, 5);
323                assert_eq!(max_length, 10);
324            }
325            _ => panic!("Wrong generator type"),
326        }
327    }
328
329    #[test]
330    fn test_generator_type_int() {
331        let gen_type = GeneratorType::Int { min: 1, max: 100 };
332
333        match gen_type {
334            GeneratorType::Int { min, max } => {
335                assert_eq!(min, 1);
336                assert_eq!(max, 100);
337            }
338            _ => panic!("Wrong generator type"),
339        }
340    }
341
342    #[test]
343    fn test_generator_type_float() {
344        let gen_type = GeneratorType::Float { min: 0.0, max: 1.0 };
345
346        match gen_type {
347            GeneratorType::Float { min, max } => {
348                assert_eq!(min, 0.0);
349                assert_eq!(max, 1.0);
350            }
351            _ => panic!("Wrong generator type"),
352        }
353    }
354
355    #[test]
356    fn test_generator_type_uuid() {
357        let gen_type = GeneratorType::Uuid;
358        assert!(matches!(gen_type, GeneratorType::Uuid));
359    }
360
361    #[test]
362    fn test_generator_type_email() {
363        let gen_type = GeneratorType::Email;
364        assert!(matches!(gen_type, GeneratorType::Email));
365    }
366
367    #[test]
368    fn test_generator_type_name() {
369        let gen_type = GeneratorType::Name;
370        assert!(matches!(gen_type, GeneratorType::Name));
371    }
372
373    #[test]
374    fn test_generator_type_timestamp() {
375        let gen_type = GeneratorType::Timestamp;
376        assert!(matches!(gen_type, GeneratorType::Timestamp));
377    }
378
379    #[test]
380    fn test_generator_type_from_list() {
381        let values = vec![serde_json::json!("value1"), serde_json::json!("value2")];
382        let gen_type = GeneratorType::FromList {
383            values: values.clone(),
384        };
385
386        match gen_type {
387            GeneratorType::FromList { values: v } => {
388                assert_eq!(v.len(), 2);
389            }
390            _ => panic!("Wrong generator type"),
391        }
392    }
393
394    #[test]
395    fn test_resolver_registry_new() {
396        let registry = ResolverRegistry::new();
397        assert_eq!(registry.resolvers.len(), 0);
398    }
399
400    #[test]
401    fn test_resolver_registry_default() {
402        let registry = ResolverRegistry::default();
403        assert_eq!(registry.resolvers.len(), 0);
404    }
405
406    #[test]
407    fn test_resolver_registry_register() {
408        let mut registry = ResolverRegistry::new();
409
410        let resolver = MockResolver {
411            field_name: "id".to_string(),
412            field_type: "ID!".to_string(),
413            mock_data: Value::String("test-id".to_string()),
414            generator: None,
415        };
416
417        registry.register_resolver("User", resolver);
418
419        assert!(registry.resolvers.contains_key("User"));
420        assert!(registry.resolvers.get("User").unwrap().contains_key("id"));
421    }
422
423    #[test]
424    fn test_resolver_registry_get_resolver() {
425        let mut registry = ResolverRegistry::new();
426
427        let resolver = MockResolver {
428            field_name: "email".to_string(),
429            field_type: "String!".to_string(),
430            mock_data: Value::String("test@example.com".to_string()),
431            generator: None,
432        };
433
434        registry.register_resolver("User", resolver);
435
436        let retrieved = registry.get_resolver("User", "email");
437        assert!(retrieved.is_some());
438        assert_eq!(retrieved.unwrap().field_name, "email");
439    }
440
441    #[test]
442    fn test_resolver_registry_get_resolver_not_found() {
443        let registry = ResolverRegistry::new();
444        let retrieved = registry.get_resolver("User", "unknown");
445        assert!(retrieved.is_none());
446    }
447
448    #[tokio::test]
449    async fn test_generate_mock_data_with_static_data() {
450        let mut registry = ResolverRegistry::new();
451
452        let resolver = MockResolver {
453            field_name: "name".to_string(),
454            field_type: "String!".to_string(),
455            mock_data: Value::String("John Doe".to_string()),
456            generator: None,
457        };
458
459        registry.register_resolver("User", resolver);
460
461        let result = registry.generate_mock_data("User", "name").await;
462        assert!(matches!(result, Value::String(_)));
463    }
464
465    #[tokio::test]
466    async fn test_generate_default_mock_data_id() {
467        let result = ResolverRegistry::generate_default_mock_data("id").await;
468        assert!(matches!(result, Value::String(_)));
469    }
470
471    #[tokio::test]
472    async fn test_generate_default_mock_data_name() {
473        let result = ResolverRegistry::generate_default_mock_data("name").await;
474        assert!(matches!(result, Value::String(_)));
475    }
476
477    #[tokio::test]
478    async fn test_generate_default_mock_data_email() {
479        let result = ResolverRegistry::generate_default_mock_data("email").await;
480        assert!(matches!(result, Value::String(_)));
481    }
482
483    #[tokio::test]
484    async fn test_generate_default_mock_data_age() {
485        let result = ResolverRegistry::generate_default_mock_data("age").await;
486        assert!(matches!(result, Value::Number(_)));
487    }
488
489    #[tokio::test]
490    async fn test_generate_default_mock_data_active() {
491        let result = ResolverRegistry::generate_default_mock_data("active").await;
492        assert!(matches!(result, Value::Boolean(_)));
493    }
494
495    #[test]
496    fn test_create_common_resolvers() {
497        let registry = ResolverRegistry::create_common_resolvers();
498
499        assert!(registry.get_resolver("User", "id").is_some());
500        assert!(registry.get_resolver("User", "name").is_some());
501        assert!(registry.get_resolver("User", "email").is_some());
502        assert!(registry.get_resolver("User", "createdAt").is_some());
503    }
504
505    #[tokio::test]
506    async fn test_mock_data_generator_uuid() {
507        let generator = MockDataGenerator {
508            generator_type: GeneratorType::Uuid,
509            config: HashMap::new(),
510        };
511
512        let result = generator.generate().await;
513        assert!(matches!(result, Value::String(_)));
514    }
515
516    #[tokio::test]
517    async fn test_mock_data_generator_email() {
518        let generator = MockDataGenerator {
519            generator_type: GeneratorType::Email,
520            config: HashMap::new(),
521        };
522
523        let result = generator.generate().await;
524        assert!(matches!(result, Value::String(_)));
525    }
526
527    #[tokio::test]
528    async fn test_mock_data_generator_name() {
529        let generator = MockDataGenerator {
530            generator_type: GeneratorType::Name,
531            config: HashMap::new(),
532        };
533
534        let result = generator.generate().await;
535        assert!(matches!(result, Value::String(_)));
536    }
537
538    #[tokio::test]
539    async fn test_mock_data_generator_timestamp() {
540        let generator = MockDataGenerator {
541            generator_type: GeneratorType::Timestamp,
542            config: HashMap::new(),
543        };
544
545        let result = generator.generate().await;
546        assert!(matches!(result, Value::String(_)));
547    }
548
549    #[tokio::test]
550    async fn test_mock_data_generator_int() {
551        let generator = MockDataGenerator {
552            generator_type: GeneratorType::Int { min: 1, max: 100 },
553            config: HashMap::new(),
554        };
555
556        let result = generator.generate().await;
557        assert!(matches!(result, Value::Number(_)));
558    }
559
560    #[tokio::test]
561    async fn test_mock_data_generator_float() {
562        let generator = MockDataGenerator {
563            generator_type: GeneratorType::Float {
564                min: 0.0,
565                max: 10.0,
566            },
567            config: HashMap::new(),
568        };
569
570        let result = generator.generate().await;
571        assert!(matches!(result, Value::Number(_)));
572    }
573
574    #[tokio::test]
575    async fn test_mock_data_generator_string() {
576        let generator = MockDataGenerator {
577            generator_type: GeneratorType::String {
578                min_length: 5,
579                max_length: 10,
580            },
581            config: HashMap::new(),
582        };
583
584        let result = generator.generate().await;
585        if let Value::String(s) = result {
586            assert!(s.len() >= 5);
587            assert!(s.len() <= 10);
588        } else {
589            panic!("Expected string value");
590        }
591    }
592
593    #[tokio::test]
594    async fn test_mock_data_generator_from_list() {
595        let values = vec![
596            serde_json::json!("value1"),
597            serde_json::json!("value2"),
598            serde_json::json!("value3"),
599        ];
600
601        let generator = MockDataGenerator {
602            generator_type: GeneratorType::FromList { values },
603            config: HashMap::new(),
604        };
605
606        let result = generator.generate().await;
607        assert!(matches!(result, Value::String(_)));
608    }
609
610    #[tokio::test]
611    async fn test_mock_data_generator_from_empty_list() {
612        let generator = MockDataGenerator {
613            generator_type: GeneratorType::FromList { values: vec![] },
614            config: HashMap::new(),
615        };
616
617        let result = generator.generate().await;
618        assert!(matches!(result, Value::Null));
619    }
620
621    #[tokio::test]
622    async fn test_mock_data_generator_array() {
623        let generator = MockDataGenerator {
624            generator_type: GeneratorType::Array {
625                item_generator: Box::new(GeneratorType::Uuid),
626                min_items: 2,
627                max_items: 5,
628            },
629            config: HashMap::new(),
630        };
631
632        let result = generator.generate().await;
633        if let Value::List(items) = result {
634            assert!(items.len() >= 2);
635            assert!(items.len() <= 5);
636        } else {
637            panic!("Expected list value");
638        }
639    }
640
641    #[tokio::test]
642    async fn test_resolver_registry_multiple_types() {
643        let mut registry = ResolverRegistry::new();
644
645        registry.register_resolver(
646            "User",
647            MockResolver {
648                field_name: "id".to_string(),
649                field_type: "ID!".to_string(),
650                mock_data: Value::String("user-id".to_string()),
651                generator: None,
652            },
653        );
654
655        registry.register_resolver(
656            "Post",
657            MockResolver {
658                field_name: "id".to_string(),
659                field_type: "ID!".to_string(),
660                mock_data: Value::String("post-id".to_string()),
661                generator: None,
662            },
663        );
664
665        assert!(registry.get_resolver("User", "id").is_some());
666        assert!(registry.get_resolver("Post", "id").is_some());
667    }
668
669    #[test]
670    fn test_resolver_registry_multiple_fields_same_type() {
671        let mut registry = ResolverRegistry::new();
672
673        registry.register_resolver(
674            "User",
675            MockResolver {
676                field_name: "id".to_string(),
677                field_type: "ID!".to_string(),
678                mock_data: Value::Null,
679                generator: None,
680            },
681        );
682
683        registry.register_resolver(
684            "User",
685            MockResolver {
686                field_name: "name".to_string(),
687                field_type: "String!".to_string(),
688                mock_data: Value::Null,
689                generator: None,
690            },
691        );
692
693        registry.register_resolver(
694            "User",
695            MockResolver {
696                field_name: "email".to_string(),
697                field_type: "String!".to_string(),
698                mock_data: Value::Null,
699                generator: None,
700            },
701        );
702
703        assert_eq!(registry.resolvers.get("User").unwrap().len(), 3);
704    }
705}