use rust_db_blueprint::blueprint::{Blueprint, BlueprintConfig};
#[test]
fn test_basic_draft_parsing_and_generation() {
let draft = r#"
models:
Post:
title: string:400
content: longtext
published_at: datetime nullable
author_id: unsignedBigInteger foreign:users.id
User:
name: string:100
email: string:100 unique
password: string:100
controllers:
Post:
resource: web
User:
resource: api
seeders:
- Post
- User
"#;
let blueprint = Blueprint::new(BlueprintConfig::default());
let result = blueprint.build(draft).unwrap();
assert!(!result.is_empty(), "Should generate files");
let paths: Vec<&String> = result.keys().collect();
assert!(paths.iter().any(|p| p.contains("src/models/post.rs")));
assert!(paths.iter().any(|p| p.contains("src/models/user.rs")));
assert!(paths.iter().any(|p| p.contains("src/models/mod.rs")));
assert!(paths.iter().any(|p| p.contains("migrations/")));
assert!(paths.iter().any(|p| p.contains("src/db/factories.rs")));
assert!(paths.iter().any(|p| p.contains("src/handlers/post.rs")));
assert!(paths.iter().any(|p| p.contains("src/handlers/mod.rs")));
assert!(paths.iter().any(|p| p.contains("src/routes.rs")));
assert!(paths.iter().any(|p| p.contains("tests/")));
assert!(paths.iter().any(|p| p.contains("src/db/seeds.rs")));
assert!(paths.iter().any(|p| p.contains("src/requests/")));
let post_model = result.keys()
.find(|p| p.contains("src/models/post.rs"))
.and_then(|k| result.get(k.as_str()))
.unwrap();
assert!(post_model.contains("pub struct Post"));
assert!(post_model.contains("sqlx::FromRow"));
assert!(post_model.contains("title: String"));
let migration = result.keys().find(|p| p.contains("_posts.sql")).unwrap();
let migration_content = result.get(migration.as_str()).unwrap();
assert!(migration_content.contains("CREATE TABLE posts"));
assert!(migration_content.contains("VARCHAR(400)"));
assert!(migration_content.contains("REFERENCES users(id)"));
let handler = result.keys()
.find(|p| p.contains("src/handlers/post.rs"))
.and_then(|k| result.get(k.as_str()))
.unwrap();
assert!(handler.contains("pub struct PostHandlers"));
let routes = result.get("src/routes.rs").unwrap();
assert!(routes.contains("fn app_router"));
assert!(routes.contains("axum::{Router"));
let seeds = result.get("src/db/seeds.rs").unwrap();
assert!(seeds.contains("run_all"));
}
#[test]
fn test_only_and_skip_filters() {
let draft = r#"
models:
Product:
name: string:200
price: decimal:8,2
"#;
let config = BlueprintConfig {
only: vec!["models".to_string()],
..BlueprintConfig::default()
};
let blueprint = Blueprint::new(config);
let result = blueprint.build(draft).unwrap();
assert!(result.keys().any(|p| p.contains("src/models/")));
assert!(result.keys().all(|p| !p.contains("migrations/")));
let config = BlueprintConfig {
skip: vec!["migrations".to_string(), "factories".to_string()],
..BlueprintConfig::default()
};
let blueprint = Blueprint::new(config);
let result = blueprint.build(draft).unwrap();
assert!(result.keys().any(|p| p.contains("src/models/")));
assert!(result.keys().all(|p| !p.contains("migrations/")));
assert!(result.keys().all(|p| !p.contains("src/db/factories")));
}
#[test]
fn test_model_with_relationships() {
let draft = r#"
models:
Comment:
content: text
post_id: unsignedBigInteger
controllers:
Comment:
resource: api
"#;
let blueprint = Blueprint::new(BlueprintConfig::default());
let result = blueprint.build(draft).unwrap();
let model_path = result.keys()
.find(|p| p.contains("src/models/comment.rs"))
.and_then(|k| result.get(k.as_str()))
.unwrap();
assert!(model_path.contains("pub struct Comment"));
assert!(model_path.contains("post_id: i32"));
}
#[test]
fn test_with_soft_deletes() {
let draft = r#"
models:
Post:
title: string
softDeletes: true
"#;
let blueprint = Blueprint::new(BlueprintConfig::default());
let result = blueprint.build(draft).unwrap();
let model = result.keys()
.find(|p| p.contains("src/models/post.rs"))
.and_then(|k| result.get(k.as_str()))
.unwrap();
assert!(model.contains("deleted_at: Option<chrono::NaiveDateTime>"));
let migration = result.keys().find(|p| p.contains("_posts.sql")).unwrap();
let migration_content = result.get(migration.as_str()).unwrap();
assert!(migration_content.contains("deleted_at TIMESTAMP"));
}
#[test]
fn test_pivot_model() {
let draft = r#"
models:
PostUser:
pivot: true
post_id: unsignedBigInteger
user_id: unsignedBigInteger
"#;
let blueprint = Blueprint::new(BlueprintConfig::default());
let result = blueprint.build(draft).unwrap();
let model = result.keys()
.find(|p| p.contains("src/models/post_user.rs"))
.and_then(|k| result.get(k.as_str()))
.unwrap();
assert!(model.contains("pub struct PostUser"));
}