1use crate::faker::EnhancedFaker;
4use crate::{Error, Result};
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Value};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct FieldDefinition {
12 pub name: String,
14 pub field_type: String,
16 pub required: bool,
18 pub default: Option<Value>,
20 pub constraints: HashMap<String, Value>,
22 pub faker_template: Option<String>,
24 pub description: Option<String>,
26}
27
28impl FieldDefinition {
29 pub fn new(name: String, field_type: String) -> Self {
31 Self {
32 name,
33 field_type,
34 required: true,
35 default: None,
36 constraints: HashMap::new(),
37 faker_template: None,
38 description: None,
39 }
40 }
41
42 pub fn optional(mut self) -> Self {
44 self.required = false;
45 self
46 }
47
48 pub fn with_default(mut self, default: Value) -> Self {
50 self.default = Some(default);
51 self
52 }
53
54 pub fn with_constraint(mut self, key: String, value: Value) -> Self {
56 self.constraints.insert(key, value);
57 self
58 }
59
60 pub fn with_faker_template(mut self, template: String) -> Self {
62 self.faker_template = Some(template);
63 self
64 }
65
66 pub fn with_description(mut self, description: String) -> Self {
68 self.description = Some(description);
69 self
70 }
71
72 pub fn generate_value(&self, faker: &mut EnhancedFaker) -> Value {
74 if let Some(template) = &self.faker_template {
76 return faker.generate_by_type(template);
77 }
78
79 if !self.required {
81 if let Some(default) = &self.default {
82 return default.clone();
83 }
84 }
85
86 faker.generate_by_type(&self.field_type)
88 }
89
90 pub fn validate_value(&self, value: &Value) -> Result<()> {
92 if self.required && value.is_null() {
94 return Err(Error::generic(format!("Required field '{}' is null", self.name)));
95 }
96
97 let expected_type = self
99 .constraints
100 .get("type")
101 .and_then(|v| v.as_str())
102 .unwrap_or(&self.field_type);
103
104 let actual_type = match value {
105 Value::String(_) => "string",
106 Value::Number(num) => {
107 if num.is_i64() || num.is_u64() {
109 "integer"
110 } else {
111 "number"
112 }
113 }
114 Value::Bool(_) => "boolean",
115 Value::Object(_) => "object",
116 Value::Array(_) => "array",
117 Value::Null => "null",
118 };
119
120 let normalized_expected = match expected_type {
122 "int" | "integer" => "integer",
123 "float" | "number" => "number",
124 other => other,
125 };
126
127 if normalized_expected != actual_type
128 && !(normalized_expected == "number" && actual_type == "integer")
129 && !(normalized_expected == "float" && actual_type == "number")
130 && !(normalized_expected == "integer" && actual_type == "integer")
131 && !(normalized_expected == "int" && actual_type == "integer")
132 && !(normalized_expected == "uuid" && actual_type == "string")
133 && !(normalized_expected == "email" && actual_type == "string")
134 && !(normalized_expected == "name" && actual_type == "string")
135 && !(normalized_expected == "address" && actual_type == "string")
136 && !(normalized_expected == "phone" && actual_type == "string")
137 && !(normalized_expected == "company" && actual_type == "string")
138 && !(normalized_expected == "url" && actual_type == "string")
139 && !(normalized_expected == "ip" && actual_type == "string")
140 && !(normalized_expected == "color" && actual_type == "string")
141 && !(normalized_expected == "date" && actual_type == "string")
142 && !(normalized_expected == "datetime" && actual_type == "string")
143 && !(normalized_expected == "paragraph" && actual_type == "string")
144 {
145 return Err(Error::generic(format!(
146 "Field '{}' type mismatch: expected {}, got {}",
147 self.name, normalized_expected, actual_type
148 )));
149 }
150
151 if let Value::Number(num) = value {
153 if let Some(min_val) = self.constraints.get("minimum") {
154 if let Some(min_num) = min_val.as_f64() {
155 if num.as_f64().unwrap_or(0.0) < min_num {
156 return Err(Error::generic(format!(
157 "Field '{}' value {} is less than minimum {}",
158 self.name, num, min_num
159 )));
160 }
161 }
162 }
163
164 if let Some(max_val) = self.constraints.get("maximum") {
165 if let Some(max_num) = max_val.as_f64() {
166 if num.as_f64().unwrap_or(0.0) > max_num {
167 return Err(Error::generic(format!(
168 "Field '{}' value {} is greater than maximum {}",
169 self.name, num, max_num
170 )));
171 }
172 }
173 }
174 }
175
176 if let Value::String(s) = value {
178 if let Some(min_len) = self.constraints.get("minLength") {
179 if let Some(min_len_num) = min_len.as_u64() {
180 if s.len() < min_len_num as usize {
181 return Err(Error::generic(format!(
182 "Field '{}' length {} is less than minimum {}",
183 self.name,
184 s.len(),
185 min_len_num
186 )));
187 }
188 }
189 }
190
191 if let Some(max_len) = self.constraints.get("maxLength") {
192 if let Some(max_len_num) = max_len.as_u64() {
193 if s.len() > max_len_num as usize {
194 return Err(Error::generic(format!(
195 "Field '{}' length {} is greater than maximum {}",
196 self.name,
197 s.len(),
198 max_len_num
199 )));
200 }
201 }
202 }
203 }
204
205 Ok(())
206 }
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct SchemaDefinition {
212 pub name: String,
214 pub description: Option<String>,
216 pub fields: Vec<FieldDefinition>,
218 pub relationships: HashMap<String, Relationship>,
220 pub metadata: HashMap<String, Value>,
222}
223
224impl SchemaDefinition {
225 pub fn new(name: String) -> Self {
227 Self {
228 name,
229 description: None,
230 fields: Vec::new(),
231 relationships: HashMap::new(),
232 metadata: HashMap::new(),
233 }
234 }
235
236 pub fn with_field(mut self, field: FieldDefinition) -> Self {
238 self.fields.push(field);
239 self
240 }
241
242 pub fn with_fields(mut self, fields: Vec<FieldDefinition>) -> Self {
244 self.fields.extend(fields);
245 self
246 }
247
248 pub fn with_description(mut self, description: String) -> Self {
250 self.description = Some(description);
251 self
252 }
253
254 pub fn with_relationship(mut self, name: String, relationship: Relationship) -> Self {
256 self.relationships.insert(name, relationship);
257 self
258 }
259
260 pub fn with_metadata(mut self, key: String, value: Value) -> Self {
262 self.metadata.insert(key, value);
263 self
264 }
265
266 pub fn generate_row(&self, faker: &mut EnhancedFaker) -> Result<Value> {
268 let mut row = serde_json::Map::new();
269
270 for field in &self.fields {
271 let value = field.generate_value(faker);
272 field.validate_value(&value)?;
273 row.insert(field.name.clone(), value);
274 }
275
276 Ok(Value::Object(row))
277 }
278
279 pub fn get_field(&self, name: &str) -> Option<&FieldDefinition> {
281 self.fields.iter().find(|field| field.name == name)
282 }
283
284 pub fn from_json_schema(json_schema: &Value) -> Result<Self> {
286 let title = json_schema
287 .get("title")
288 .and_then(|v| v.as_str())
289 .unwrap_or("GeneratedSchema")
290 .to_string();
291
292 let description =
293 json_schema.get("description").and_then(|v| v.as_str()).map(|s| s.to_string());
294
295 let mut schema = Self::new(title);
296 if let Some(desc) = description {
297 schema = schema.with_description(desc);
298 }
299
300 if let Some(properties) = json_schema.get("properties") {
301 if let Some(props_obj) = properties.as_object() {
302 for (name, prop_def) in props_obj {
303 let field_type = extract_type_from_json_schema(prop_def);
304 let mut field = FieldDefinition::new(name.clone(), field_type);
305
306 if let Some(required) = json_schema.get("required") {
308 if let Some(required_arr) = required.as_array() {
309 let is_required = required_arr.iter().any(|v| v.as_str() == Some(name));
310 if !is_required {
311 field = field.optional();
312 }
313 }
314 }
315
316 if let Some(desc) = prop_def.get("description").and_then(|v| v.as_str()) {
318 field = field.with_description(desc.to_string());
319 }
320
321 if let Some(minimum) = prop_def.get("minimum") {
323 field = field.with_constraint("minimum".to_string(), minimum.clone());
324 }
325 if let Some(maximum) = prop_def.get("maximum") {
326 field = field.with_constraint("maximum".to_string(), maximum.clone());
327 }
328 if let Some(min_length) = prop_def.get("minLength") {
329 field = field.with_constraint("minLength".to_string(), min_length.clone());
330 }
331 if let Some(max_length) = prop_def.get("maxLength") {
332 field = field.with_constraint("maxLength".to_string(), max_length.clone());
333 }
334 if let Some(enum_vals) = prop_def.get("enum") {
336 if let Some(_enum_arr) = enum_vals.as_array() {
337 field = field.with_constraint("enum".to_string(), enum_vals.clone());
338 }
339 }
340 if field.field_type == "array" {
342 if let Some(items) = prop_def.get("items") {
343 if items.is_object() {
345 field =
346 field.with_constraint("itemsSchema".to_string(), items.clone());
347 if let Some(items_type) = items.get("type") {
349 if let Some(items_type_str) = items_type.as_str() {
350 field = field.with_constraint(
351 "itemsType".to_string(),
352 json!(items_type_str),
353 );
354 }
355 }
356 } else if let Some(items_type) = items.as_str() {
357 field = field
359 .with_constraint("itemsType".to_string(), json!(items_type));
360 }
361 }
362 }
363 if field.field_type == "object" {
365 if let Some(properties) = prop_def.get("properties") {
366 field =
368 field.with_constraint("properties".to_string(), properties.clone());
369 if let Some(required) = prop_def.get("required") {
371 field =
372 field.with_constraint("required".to_string(), required.clone());
373 }
374 }
375 }
376 if let Some(min_items) = prop_def.get("minItems") {
378 field = field.with_constraint("minItems".to_string(), min_items.clone());
379 }
380 if let Some(max_items) = prop_def.get("maxItems") {
381 field = field.with_constraint("maxItems".to_string(), max_items.clone());
382 }
383
384 schema = schema.with_field(field);
385 }
386 }
387 }
388
389 Ok(schema)
390 }
391
392 pub fn from_openapi_spec(openapi_spec: &Value) -> Result<Self> {
394 if !openapi_spec.is_object() {
396 return Err(Error::generic("OpenAPI spec must be a JSON object"));
397 }
398
399 let spec = openapi_spec.as_object().unwrap();
400
401 let title = spec
403 .get("info")
404 .and_then(|info| info.get("title"))
405 .and_then(|title| title.as_str())
406 .unwrap_or("OpenAPI Generated Schema")
407 .to_string();
408
409 let description = spec
411 .get("info")
412 .and_then(|info| info.get("description"))
413 .and_then(|desc| desc.as_str())
414 .map(|s| s.to_string());
415
416 let mut schema = Self::new(title);
417 if let Some(desc) = description {
418 schema = schema.with_description(desc);
419 }
420
421 if let Some(paths) = spec.get("paths").and_then(|p| p.as_object()) {
423 for (path, path_item) in paths {
424 if let Some(path_obj) = path_item.as_object() {
425 for (method, operation) in path_obj {
427 if let Some(op_obj) = operation.as_object() {
428 if let Some(request_body) = op_obj.get("requestBody") {
430 if let Some(rb_obj) = request_body.as_object() {
431 if let Some(content) = rb_obj.get("content") {
432 if let Some(json_content) = content.get("application/json")
433 {
434 if let Some(schema_obj) = json_content.get("schema") {
435 let field_name = format!(
436 "{}_{}_request",
437 path.replace("/", "_").trim_start_matches("_"),
438 method
439 );
440 if let Some(field) =
441 Self::create_field_from_openapi_schema(
442 &field_name,
443 schema_obj,
444 )
445 {
446 schema = schema.with_field(field);
447 }
448 }
449 }
450 }
451 }
452 }
453
454 if let Some(responses) = op_obj.get("responses") {
456 if let Some(resp_obj) = responses.as_object() {
457 for (status_code, response) in resp_obj {
459 if status_code == "200"
460 || status_code == "201"
461 || status_code.starts_with("2")
462 {
463 if let Some(resp_obj) = response.as_object() {
464 if let Some(content) = resp_obj.get("content") {
465 if let Some(json_content) =
466 content.get("application/json")
467 {
468 if let Some(schema_obj) =
469 json_content.get("schema")
470 {
471 let field_name = format!(
472 "{}_{}_response_{}",
473 path.replace("/", "_")
474 .trim_start_matches("_"),
475 method,
476 status_code
477 );
478 if let Some(field) = Self::create_field_from_openapi_schema(&field_name, schema_obj) {
479 schema = schema.with_field(field);
480 }
481 }
482 }
483 }
484 }
485 }
486 }
487 }
488 }
489 }
490 }
491 }
492 }
493 }
494
495 if let Some(components) = spec.get("components") {
497 if let Some(comp_obj) = components.as_object() {
498 if let Some(schemas) = comp_obj.get("schemas") {
499 if let Some(schema_obj) = schemas.as_object() {
500 for (name, schema_def) in schema_obj {
501 if let Some(field) =
502 Self::create_field_from_openapi_schema(name, schema_def)
503 {
504 schema = schema.with_field(field);
505 }
506 }
507 }
508 }
509 }
510 }
511
512 Ok(schema)
513 }
514
515 fn create_field_from_openapi_schema(name: &str, schema: &Value) -> Option<FieldDefinition> {
517 if !schema.is_object() {
518 return None;
519 }
520
521 let schema_obj = schema.as_object().unwrap();
522
523 let field_type = if let Some(type_val) = schema_obj.get("type") {
525 if let Some(type_str) = type_val.as_str() {
526 match type_str {
527 "string" => "string".to_string(),
528 "number" => "float".to_string(),
529 "integer" => "int".to_string(),
530 "boolean" => "boolean".to_string(),
531 "object" => "object".to_string(),
532 "array" => "array".to_string(),
533 _ => "string".to_string(),
534 }
535 } else {
536 "string".to_string()
537 }
538 } else {
539 "string".to_string()
540 };
541
542 let mut field = FieldDefinition::new(name.to_string(), field_type);
543
544 if let Some(desc) = schema_obj.get("description").and_then(|d| d.as_str()) {
546 field = field.with_description(desc.to_string());
547 }
548
549 if let Some(required) = schema_obj.get("required") {
551 if let Some(required_arr) = required.as_array() {
552 if !required_arr.iter().any(|v| v.as_str() == Some(name)) {
553 field = field.optional();
554 }
555 }
556 }
557
558 if let Some(minimum) = schema_obj.get("minimum") {
560 field = field.with_constraint("minimum".to_string(), minimum.clone());
561 }
562 if let Some(maximum) = schema_obj.get("maximum") {
563 field = field.with_constraint("maximum".to_string(), maximum.clone());
564 }
565 if let Some(min_length) = schema_obj.get("minLength") {
566 field = field.with_constraint("minLength".to_string(), min_length.clone());
567 }
568 if let Some(max_length) = schema_obj.get("maxLength") {
569 field = field.with_constraint("maxLength".to_string(), max_length.clone());
570 }
571
572 if let Some(enum_vals) = schema_obj.get("enum") {
574 if let Some(_enum_arr) = enum_vals.as_array() {
575 field = field.with_constraint("enum".to_string(), enum_vals.clone());
576 }
577 }
578
579 Some(field)
580 }
581}
582
583#[derive(Debug, Clone, Serialize, Deserialize)]
585pub struct Relationship {
586 pub target_schema: String,
588 pub relationship_type: RelationshipType,
590 pub foreign_key: String,
592 pub required: bool,
594}
595
596impl Relationship {
597 pub fn new(
599 target_schema: String,
600 relationship_type: RelationshipType,
601 foreign_key: String,
602 ) -> Self {
603 Self {
604 target_schema,
605 relationship_type,
606 foreign_key,
607 required: true,
608 }
609 }
610
611 pub fn optional(mut self) -> Self {
613 self.required = false;
614 self
615 }
616}
617
618#[derive(Debug, Clone, Serialize, Deserialize)]
620#[serde(rename_all = "lowercase")]
621pub enum RelationshipType {
622 OneToOne,
624 OneToMany,
626 ManyToOne,
628 ManyToMany,
630}
631
632fn extract_type_from_json_schema(prop_def: &Value) -> String {
634 if let Some(type_val) = prop_def.get("type") {
635 if let Some(type_str) = type_val.as_str() {
636 return match type_str {
637 "string" => "string".to_string(),
638 "number" => "float".to_string(),
639 "integer" => "int".to_string(),
640 "boolean" => "boolean".to_string(),
641 "object" => "object".to_string(),
642 "array" => "array".to_string(),
643 "null" => "null".to_string(),
644 _ => "string".to_string(),
645 };
646 }
647 }
648
649 "string".to_string()
651}
652
653pub mod templates {
655 use super::*;
656
657 pub fn user_schema() -> SchemaDefinition {
659 SchemaDefinition::new("User".to_string())
660 .with_description("User account information".to_string())
661 .with_fields(vec![
662 FieldDefinition::new("id".to_string(), "uuid".to_string()),
663 FieldDefinition::new("email".to_string(), "email".to_string()),
664 FieldDefinition::new("name".to_string(), "name".to_string()),
665 FieldDefinition::new("created_at".to_string(), "date".to_string()),
666 FieldDefinition::new("active".to_string(), "boolean".to_string()),
667 ])
668 }
669
670 pub fn product_schema() -> SchemaDefinition {
672 SchemaDefinition::new("Product".to_string())
673 .with_description("Product catalog item".to_string())
674 .with_fields(vec![
675 FieldDefinition::new("id".to_string(), "uuid".to_string()),
676 FieldDefinition::new("name".to_string(), "string".to_string()),
677 FieldDefinition::new("description".to_string(), "paragraph".to_string()),
678 FieldDefinition::new("price".to_string(), "float".to_string())
679 .with_constraint("minimum".to_string(), Value::Number(0.into())),
680 FieldDefinition::new("category".to_string(), "string".to_string()),
681 FieldDefinition::new("in_stock".to_string(), "boolean".to_string()),
682 ])
683 }
684
685 pub fn order_schema() -> SchemaDefinition {
687 SchemaDefinition::new("Order".to_string())
688 .with_description("Customer order".to_string())
689 .with_fields(vec![
690 FieldDefinition::new("id".to_string(), "uuid".to_string()),
691 FieldDefinition::new("user_id".to_string(), "uuid".to_string()),
692 FieldDefinition::new("total_amount".to_string(), "float".to_string())
693 .with_constraint("minimum".to_string(), Value::Number(0.into())),
694 FieldDefinition::new("status".to_string(), "string".to_string()),
695 FieldDefinition::new("created_at".to_string(), "date".to_string()),
696 ])
697 .with_relationship(
698 "user".to_string(),
699 Relationship::new(
700 "User".to_string(),
701 RelationshipType::ManyToOne,
702 "user_id".to_string(),
703 ),
704 )
705 }
706}
707
708#[cfg(test)]
709mod tests {
710 use super::*;
711
712 #[test]
713 fn test_field_definition_new() {
714 let field = FieldDefinition::new("test".to_string(), "string".to_string());
715
716 assert_eq!(field.name, "test");
717 assert_eq!(field.field_type, "string");
718 assert!(field.required);
719 assert!(field.default.is_none());
720 }
721
722 #[test]
723 fn test_field_definition_optional() {
724 let field = FieldDefinition::new("test".to_string(), "string".to_string()).optional();
725
726 assert!(!field.required);
727 }
728
729 #[test]
730 fn test_field_definition_with_default() {
731 let field = FieldDefinition::new("test".to_string(), "string".to_string())
732 .with_default(Value::String("default".to_string()));
733
734 assert_eq!(field.default, Some(Value::String("default".to_string())));
735 }
736
737 #[test]
738 fn test_field_definition_with_constraint() {
739 let field = FieldDefinition::new("age".to_string(), "int".to_string())
740 .with_constraint("minimum".to_string(), Value::Number(0.into()));
741
742 assert!(field.constraints.contains_key("minimum"));
743 }
744
745 #[test]
746 fn test_field_definition_with_faker_template() {
747 let field = FieldDefinition::new("email".to_string(), "string".to_string())
748 .with_faker_template("email".to_string());
749
750 assert_eq!(field.faker_template, Some("email".to_string()));
751 }
752
753 #[test]
754 fn test_field_definition_with_description() {
755 let field = FieldDefinition::new("test".to_string(), "string".to_string())
756 .with_description("Test field".to_string());
757
758 assert_eq!(field.description, Some("Test field".to_string()));
759 }
760
761 #[test]
762 fn test_schema_definition_new() {
763 let schema = SchemaDefinition::new("TestSchema".to_string());
764
765 assert_eq!(schema.name, "TestSchema");
766 assert!(schema.description.is_none());
767 assert_eq!(schema.fields.len(), 0);
768 }
769
770 #[test]
771 fn test_schema_definition_with_field() {
772 let field = FieldDefinition::new("id".to_string(), "uuid".to_string());
773 let schema = SchemaDefinition::new("Test".to_string()).with_field(field);
774
775 assert_eq!(schema.fields.len(), 1);
776 assert_eq!(schema.fields[0].name, "id");
777 }
778
779 #[test]
780 fn test_schema_definition_with_fields() {
781 let fields = vec![
782 FieldDefinition::new("id".to_string(), "uuid".to_string()),
783 FieldDefinition::new("name".to_string(), "string".to_string()),
784 ];
785 let schema = SchemaDefinition::new("Test".to_string()).with_fields(fields);
786
787 assert_eq!(schema.fields.len(), 2);
788 }
789
790 #[test]
791 fn test_schema_definition_with_description() {
792 let schema =
793 SchemaDefinition::new("Test".to_string()).with_description("Test schema".to_string());
794
795 assert_eq!(schema.description, Some("Test schema".to_string()));
796 }
797
798 #[test]
799 fn test_schema_definition_with_metadata() {
800 let schema = SchemaDefinition::new("Test".to_string())
801 .with_metadata("version".to_string(), Value::String("1.0".to_string()));
802
803 assert!(schema.metadata.contains_key("version"));
804 }
805
806 #[test]
807 fn test_schema_definition_get_field() {
808 let field = FieldDefinition::new("email".to_string(), "email".to_string());
809 let schema = SchemaDefinition::new("Test".to_string()).with_field(field);
810
811 assert!(schema.get_field("email").is_some());
812 assert!(schema.get_field("unknown").is_none());
813 }
814
815 #[test]
816 fn test_relationship_new() {
817 let rel = Relationship::new(
818 "User".to_string(),
819 RelationshipType::ManyToOne,
820 "user_id".to_string(),
821 );
822
823 assert_eq!(rel.target_schema, "User");
824 assert_eq!(rel.foreign_key, "user_id");
825 assert!(rel.required);
826 }
827
828 #[test]
829 fn test_relationship_optional() {
830 let rel = Relationship::new(
831 "User".to_string(),
832 RelationshipType::ManyToOne,
833 "user_id".to_string(),
834 )
835 .optional();
836
837 assert!(!rel.required);
838 }
839
840 #[test]
841 fn test_relationship_types() {
842 let one_to_one = RelationshipType::OneToOne;
843 let one_to_many = RelationshipType::OneToMany;
844 let many_to_one = RelationshipType::ManyToOne;
845 let many_to_many = RelationshipType::ManyToMany;
846
847 assert!(matches!(one_to_one, RelationshipType::OneToOne));
848 assert!(matches!(one_to_many, RelationshipType::OneToMany));
849 assert!(matches!(many_to_one, RelationshipType::ManyToOne));
850 assert!(matches!(many_to_many, RelationshipType::ManyToMany));
851 }
852
853 #[test]
854 fn test_extract_type_from_json_schema_string() {
855 let prop = serde_json::json!({"type": "string"});
856 let type_str = extract_type_from_json_schema(&prop);
857
858 assert_eq!(type_str, "string");
859 }
860
861 #[test]
862 fn test_extract_type_from_json_schema_number() {
863 let prop = serde_json::json!({"type": "number"});
864 let type_str = extract_type_from_json_schema(&prop);
865
866 assert_eq!(type_str, "float");
867 }
868
869 #[test]
870 fn test_extract_type_from_json_schema_integer() {
871 let prop = serde_json::json!({"type": "integer"});
872 let type_str = extract_type_from_json_schema(&prop);
873
874 assert_eq!(type_str, "int");
875 }
876
877 #[test]
878 fn test_extract_type_from_json_schema_boolean() {
879 let prop = serde_json::json!({"type": "boolean"});
880 let type_str = extract_type_from_json_schema(&prop);
881
882 assert_eq!(type_str, "boolean");
883 }
884
885 #[test]
886 fn test_extract_type_from_json_schema_default() {
887 let prop = serde_json::json!({});
888 let type_str = extract_type_from_json_schema(&prop);
889
890 assert_eq!(type_str, "string");
891 }
892
893 #[test]
894 fn test_user_schema_template() {
895 let schema = templates::user_schema();
896
897 assert_eq!(schema.name, "User");
898 assert_eq!(schema.fields.len(), 5);
899 assert!(schema.get_field("id").is_some());
900 assert!(schema.get_field("email").is_some());
901 }
902
903 #[test]
904 fn test_product_schema_template() {
905 let schema = templates::product_schema();
906
907 assert_eq!(schema.name, "Product");
908 assert!(schema.get_field("price").is_some());
909 }
910
911 #[test]
912 fn test_order_schema_template() {
913 let schema = templates::order_schema();
914
915 assert_eq!(schema.name, "Order");
916 assert_eq!(schema.relationships.len(), 1);
917 assert!(schema.relationships.contains_key("user"));
918 }
919}