use prax_orm::schema::{PraxConfig, parse_schema, validate_schema};
#[test]
fn test_parse_model_with_all_field_types() {
let schema = parse_schema(
r#"
model AllTypes {
id Int @id @auto
bigInt BigInt
float Float
decimal Decimal
string String
boolean Boolean
dateTime DateTime
date Date
time Time
json Json
bytes Bytes
uuid Uuid
optional String?
list String[]
}
"#,
)
.expect("Failed to parse schema");
let model = schema.get_model("AllTypes").expect("Model not found");
assert_eq!(model.fields.len(), 14);
}
#[test]
fn test_parse_model_with_all_attributes() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
email String @unique @index
name String? @default("Anonymous")
password String @omit
createdAt DateTime @default(now())
updatedAt DateTime @updated_at
role String @map("user_role")
bio String? @db.Text
@@map("users")
@@index([email, name])
@@unique([email])
}
"#,
)
.expect("Failed to parse schema");
let model = schema.get_model("User").expect("Model not found");
let id_field = model.fields.get("id").expect("id field not found");
assert!(id_field.attributes.iter().any(|a| a.name.name == "id"));
assert!(id_field.attributes.iter().any(|a| a.name.name == "auto"));
assert!(model.attributes.iter().any(|a| a.name.name == "map"));
}
#[test]
fn test_parse_relations() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
email String @unique
posts Post[]
profile Profile?
}
model Post {
id Int @id @auto
title String
authorId Int
author User @relation(fields: [authorId], references: [id])
}
model Profile {
id Int @id @auto
bio String?
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
"#,
)
.expect("Failed to parse schema");
assert_eq!(schema.model_names().count(), 3);
let user = schema.get_model("User").unwrap();
assert!(user.fields.contains_key("posts"));
assert!(user.fields.contains_key("profile"));
let post = schema.get_model("Post").unwrap();
let author_field = post.fields.get("author").expect("author field not found");
assert!(
author_field
.attributes
.iter()
.any(|a| a.name.name == "relation")
);
}
#[test]
fn test_parse_self_referential_relation() {
let schema = parse_schema(
r#"
model Category {
id Int @id @auto
name String
parentId Int?
parent Category? @relation("CategoryTree", fields: [parentId], references: [id])
children Category[] @relation("CategoryTree")
}
"#,
)
.expect("Failed to parse schema");
let category = schema.get_model("Category").unwrap();
assert_eq!(category.fields.len(), 5); }
#[test]
fn test_parse_enums() {
let schema = parse_schema(
r#"
enum Role {
User
Admin
Moderator
}
enum Status {
Draft
Published
Archived
@@map("post_status")
}
model User {
id Int @id @auto
role Role @default(User)
}
"#,
)
.expect("Failed to parse schema");
assert_eq!(schema.enum_names().count(), 2);
let role = schema.get_enum("Role").unwrap();
assert_eq!(role.variants.len(), 3);
let status = schema.get_enum("Status").unwrap();
assert!(status.attributes.iter().any(|a| a.name.name == "map"));
}
#[test]
fn test_parse_composite_types() {
let schema = parse_schema(
r#"
type Address {
street String
city String
state String?
postalCode String
country String @default("US")
}
type GeoPoint {
latitude Float
longitude Float
}
model User {
id Int @id @auto
address Address
}
"#,
)
.expect("Failed to parse schema");
assert_eq!(schema.types.len(), 2);
let address = schema.get_type("Address").unwrap();
assert_eq!(address.fields.len(), 5);
}
#[test]
fn test_parse_views() {
let schema = parse_schema(
r#"
model Post {
id Int @id @auto
title String
viewCount Int @default(0)
}
view PopularPosts {
id Int @unique
title String
viewCount Int
@@map("popular_posts_view")
}
"#,
)
.expect("Failed to parse schema");
let stats = schema.stats();
assert_eq!(stats.model_count, 1, "Should have 1 model (Post)");
assert_eq!(stats.view_count, 1, "Should have 1 view (PopularPosts)");
let view = schema.get_view("PopularPosts");
assert!(view.is_some(), "PopularPosts view should exist");
let view = view.unwrap();
assert_eq!(view.fields.len(), 3, "View should have 3 fields");
}
#[test]
fn test_parse_server_groups() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
email String @unique
}
serverGroup MainCluster {
server primary {
url = "postgresql://primary:5432/db"
role = "primary"
}
server replica1 {
url = "postgresql://replica1:5432/db"
role = "replica"
weight = 50
}
@@strategy("ReadReplica")
@@loadBalance("RoundRobin")
}
"#,
)
.expect("Failed to parse schema");
assert_eq!(schema.server_group_names().count(), 1);
let sg = schema.get_server_group("MainCluster").unwrap();
assert_eq!(sg.servers.len(), 2);
}
#[test]
fn test_parse_documentation() {
let schema = parse_schema(
r#"/// User account in the system.
/// Contains authentication and profile information.
model User {
/// Primary key
id Int @id @auto
/// User's email address
email String @unique
}
"#,
)
.expect("Failed to parse schema");
let user = schema.get_model("User").unwrap();
if let Some(doc) = &user.documentation {
assert!(doc.text.to_lowercase().contains("user"));
}
}
#[test]
fn test_validate_valid_schema() {
let result = validate_schema(
r#"
model User {
id Int @id @auto
email String @unique
posts Post[]
}
model Post {
id Int @id @auto
title String
authorId Int
author User @relation(fields: [authorId], references: [id])
}
"#,
);
assert!(result.is_ok(), "Schema should be valid: {:?}", result.err());
}
#[test]
fn test_validate_missing_id() {
let result = validate_schema(
r#"
model User {
email String @unique
name String
}
"#,
);
match result {
Ok(_) => {} Err(e) => {
assert!(
e.to_string().contains("id") || e.to_string().contains("primary"),
"Error should mention missing id: {}",
e
);
}
}
}
#[test]
fn test_schema_statistics() {
let schema = parse_schema(
r#"
model User { id Int @id @auto }
model Post { id Int @id @auto }
model Comment { id Int @id @auto }
enum Role { User Admin }
enum Status { Draft Published }
type Address { street String }
view UserStats { id Int @unique }
serverGroup Cluster {
server primary { url = "postgres://localhost/db" }
}
"#,
)
.expect("Failed to parse schema");
let stats = schema.stats();
assert_eq!(stats.model_count, 3);
assert_eq!(stats.enum_count, 2);
assert_eq!(stats.type_count, 1);
assert_eq!(stats.view_count, 1);
assert_eq!(stats.server_group_count, 1);
}
#[test]
fn test_config_parsing() {
let config_str = r#"
[database]
provider = "postgresql"
url = "postgresql://localhost:5432/mydb"
[database.pool]
min_connections = 2
max_connections = 10
[generator.client]
output = "./src/generated"
[migrations]
directory = "./prax/migrations"
"#;
let config: PraxConfig = toml::from_str(config_str).expect("Failed to parse config");
assert_eq!(
config.database.url,
Some("postgresql://localhost:5432/mydb".to_string())
);
assert_eq!(config.database.pool.min_connections, 2);
assert_eq!(config.database.pool.max_connections, 10);
}
#[test]
fn test_config_with_env_vars() {
let config_str = r#"
[database]
provider = "postgresql"
url = "${DATABASE_URL}"
"#;
let config: PraxConfig = toml::from_str(config_str).expect("Failed to parse config");
assert_eq!(config.database.url, Some("${DATABASE_URL}".to_string()));
}
#[test]
fn test_schema_merging() {
let schema1 = parse_schema(
r#"
model User {
id Int @id @auto
email String @unique
}
"#,
)
.expect("Failed to parse schema 1");
let schema2 = parse_schema(
r#"
model Post {
id Int @id @auto
title String
}
"#,
)
.expect("Failed to parse schema 2");
let mut merged = schema1;
merged.merge(schema2);
assert_eq!(merged.model_names().count(), 2);
assert!(merged.get_model("User").is_some());
assert!(merged.get_model("Post").is_some());
}
#[test]
fn test_parse_indexes() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
email String @unique @index
firstName String
lastName String
createdAt DateTime
@@index([firstName, lastName])
@@index([createdAt], map: "idx_created")
@@unique([email, firstName])
}
"#,
)
.expect("Failed to parse schema");
let user = schema.get_model("User").unwrap();
let index_count = user
.attributes
.iter()
.filter(|a| a.name.name == "index")
.count();
let unique_count = user
.attributes
.iter()
.filter(|a| a.name.name == "unique")
.count();
assert!(index_count >= 2, "Should have at least 2 indexes");
assert!(
unique_count >= 1,
"Should have at least 1 unique constraint"
);
}
#[test]
fn test_parse_default_values() {
let schema = parse_schema(
r#"
model Post {
id Int @id @auto
title String
views Int @default(0)
rating Float @default(0.0)
published Boolean @default(false)
content String @default("")
status Status @default(Draft)
createdAt DateTime @default(now())
uuid String @default(uuid())
cuid String @default(cuid())
}
enum Status {
Draft
Published
}
"#,
)
.expect("Failed to parse schema");
let post = schema.get_model("Post").unwrap();
let views = post.fields.get("views").expect("views field not found");
assert!(views.attributes.iter().any(|a| a.name.name == "default"));
let created_at = post
.fields
.get("createdAt")
.expect("createdAt field not found");
assert!(
created_at
.attributes
.iter()
.any(|a| a.name.name == "default")
);
}
#[test]
fn test_parse_db_types() {
let schema = parse_schema(
r#"
model Content {
id Int @id @auto
title String @db.VarChar(200)
description String? @db.Text
metadata String? @db.Json
data Bytes? @db.ByteA
}
"#,
)
.expect("Failed to parse schema");
let content = schema.get_model("Content").unwrap();
let title = content.fields.get("title").expect("title field not found");
let has_db_attr = title
.attributes
.iter()
.any(|a| a.name.name == "db.VarChar" || a.name.name.starts_with("db"));
assert!(has_db_attr, "title should have @db attribute");
}
#[test]
fn test_parse_referential_actions() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
posts Post[]
}
model Post {
id Int @id @auto
authorId Int
author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
}
"#,
)
.expect("Failed to parse schema");
let post = schema.get_model("Post").unwrap();
let author = post.fields.get("author").expect("author field not found");
let relation = author
.attributes
.iter()
.find(|a| a.name.name == "relation")
.expect("relation attribute not found");
assert!(!relation.args.is_empty());
}
#[test]
fn test_field_names_unique() {
let schema = parse_schema(
r#"
model User {
id Int @id @auto
email String
name String
}
"#,
)
.expect("Failed to parse schema");
let user = schema.get_model("User").unwrap();
assert_eq!(user.fields.len(), 3);
}
#[test]
fn test_multiple_models() {
let schema = parse_schema(
r#"
model User { id Int @id @auto }
model Post { id Int @id @auto }
model Comment { id Int @id @auto }
model Tag { id Int @id @auto }
model Category { id Int @id @auto }
"#,
)
.expect("Failed to parse schema");
assert_eq!(schema.model_names().count(), 5);
}