#![allow(dead_code)]
use pgorm::{FromRow, InsertModel, Model, UpdateModel};
#[derive(InsertModel)]
#[orm(table = "users")]
#[orm(input)]
struct NewUser {
#[orm(len = "2..=100")]
name: String,
#[orm(email)]
email: String,
#[orm(range = "0..=150")]
age: Option<i32>,
#[orm(uuid, input_as = "String")]
external_id: uuid::Uuid,
#[orm(url)]
homepage: String,
#[orm(one_of = "free|pro|enterprise")]
plan: String,
#[orm(regex = r"^[a-z0-9_]+$")]
username: String,
#[orm(ip, input_as = "String")]
last_ip: Option<std::net::IpAddr>,
}
#[test]
fn validate_and_convert() {
let bad = NewUserInput {
name: Some("A".into()),
email: Some("not-an-email".into()),
age: Some(200),
external_id: Some("not-a-uuid".into()),
homepage: Some("not-a-url".into()),
plan: Some("gold".into()),
username: Some("bad space".into()),
last_ip: Some("not-an-ip".into()),
};
let errs = bad.validate();
assert!(!errs.is_empty());
assert!(
errs.iter()
.any(|e| e.field == "name" && e.code.as_str() == "len")
);
assert!(
errs.iter()
.any(|e| e.field == "email" && e.code.as_str() == "email")
);
assert!(
errs.iter()
.any(|e| e.field == "age" && e.code.as_str() == "range")
);
assert!(
errs.iter()
.any(|e| e.field == "external_id" && e.code.as_str() == "uuid")
);
assert!(
errs.iter()
.any(|e| e.field == "homepage" && e.code.as_str() == "url")
);
assert!(
errs.iter()
.any(|e| e.field == "plan" && e.code.as_str() == "one_of")
);
assert!(
errs.iter()
.any(|e| e.field == "username" && e.code.as_str() == "regex")
);
assert!(
errs.iter()
.any(|e| e.field == "last_ip" && e.code.as_str() == "ip")
);
let ok = NewUserInput {
name: Some("Alice".into()),
email: Some("alice@example.com".into()),
age: Some(42),
external_id: Some("550e8400-e29b-41d4-a716-446655440000".into()),
homepage: Some("https://example.com".into()),
plan: Some("pro".into()),
username: Some("alice_42".into()),
last_ip: Some("1.2.3.4".into()),
};
let user = ok.try_into_model().unwrap();
assert_eq!(user.name, "Alice");
assert_eq!(user.email, "alice@example.com");
assert_eq!(user.age, Some(42));
assert_eq!(
user.external_id.to_string(),
"550e8400-e29b-41d4-a716-446655440000"
);
assert_eq!(user.homepage, "https://example.com");
assert_eq!(user.plan, "pro");
assert_eq!(user.username, "alice_42");
assert_eq!(user.last_ip.unwrap().to_string(), "1.2.3.4");
}
#[derive(Debug, FromRow, Model)]
#[orm(table = "users")]
struct User {
#[orm(id)]
id: i64,
username: String,
email: String,
}
#[derive(UpdateModel)]
#[orm(table = "users", model = "User", returning = "User")]
#[orm(input)]
struct UserPatch {
#[orm(len = "2..=20")]
username: Option<String>,
#[orm(email)]
email: Option<String>,
#[orm(ip, input_as = "String")]
ip_address: Option<std::net::IpAddr>,
}
#[test]
fn validate_update_patch() {
let bad = UserPatchInput {
username: Some("A".into()),
email: Some("bad".into()),
ip_address: Some("bad-ip".into()),
};
let errs = bad.validate();
assert!(!errs.is_empty());
assert!(
errs.iter()
.any(|e| e.field == "username" && e.code.as_str() == "len")
);
assert!(
errs.iter()
.any(|e| e.field == "email" && e.code.as_str() == "email")
);
assert!(
errs.iter()
.any(|e| e.field == "ip_address" && e.code.as_str() == "ip")
);
let ok = UserPatchInput {
username: Some("alice".into()),
email: Some("alice@example.com".into()),
ip_address: Some("2001:db8::1".into()),
};
let patch = ok.try_into_patch().unwrap();
assert_eq!(patch.username.as_deref(), Some("alice"));
assert_eq!(patch.email.as_deref(), Some("alice@example.com"));
assert_eq!(patch.ip_address.unwrap().to_string(), "2001:db8::1");
}