use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use assert_cmd::cargo::CommandCargoExt;
use tempfile::TempDir;
const SCHEMA: &str = r#"
datasource db {
provider = "postgresql"
url = "postgres://localhost/test"
}
enum GrantKind {
Firm
User
}
/// Same shape as the lexmata `access_grants` / `firm_access_policies` /
/// `firm_roles` models that first hit the missing impls.
model AccessGrant {
id String @id @default(uuid())
kind GrantKind
scopes String[]
allowed_scopes String[] @default(dbgenerated("ARRAY[]::TEXT[]"))
labels String[]?
note String?
@@map("access_grants")
}
"#;
const LIB_RS: &str = r#"
#![deny(warnings)]
pub mod generated;
use generated::AccessGrant;
use prax_query::filter::FilterValue;
use prax_query::traits::ModelWithPk;
/// Exercises the generated client surface for a model with list fields.
pub fn find_grants<E: prax_query::QueryEngine>(client: &generated::PraxClient<E>) {
let _ = client.access_grant().find_many();
}
/// Reads list-field values back out of a model instance.
pub fn scope_values(grant: &AccessGrant) -> Option<FilterValue> {
grant.get_column_value("scopes")
}
"#;
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("prax-cli lives inside the workspace")
.to_path_buf()
}
#[test]
fn generated_client_with_string_list_fields_compiles() {
let root = workspace_root();
let temp = TempDir::new().unwrap();
let krate = temp.path().join("generated_check");
let src = krate.join("src");
fs::create_dir_all(&src).unwrap();
let schema_path = temp.path().join("schema.prax");
fs::write(&schema_path, SCHEMA).unwrap();
#[allow(deprecated)]
let status = Command::cargo_bin("prax")
.unwrap()
.args(["generate", "--schema"])
.arg(&schema_path)
.arg("--output")
.arg(src.join("generated"))
.status()
.expect("run prax generate");
assert!(status.success(), "prax generate failed");
let generated = fs::read_to_string(src.join("generated").join("access_grant.rs")).unwrap();
assert!(generated.contains("pub scopes: Vec<String>"), "{generated}");
assert!(
generated.contains("pub labels: Option<Vec<String>>"),
"{generated}"
);
let prax_query = root.join("prax-query");
fs::write(
krate.join("Cargo.toml"),
format!(
r#"[package]
name = "prax-generated-compile-check"
version = "0.0.0"
edition = "2024"
publish = false
[dependencies]
prax-query = {{ path = {prax_query:?} }}
serde = {{ version = "1", features = ["derive"] }}
serde_json = "1"
chrono = {{ version = "0.4", features = ["serde"] }}
uuid = {{ version = "1", features = ["serde"] }}
rust_decimal = {{ version = "1", features = ["serde"] }}
[workspace]
"#
),
)
.unwrap();
fs::write(src.join("lib.rs"), LIB_RS).unwrap();
fs::copy(root.join("Cargo.lock"), krate.join("Cargo.lock")).unwrap();
let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
let output = Command::new(cargo)
.args(["check", "--offline", "--quiet", "--manifest-path"])
.arg(krate.join("Cargo.toml"))
.env(
"CARGO_TARGET_DIR",
root.join("target").join("generated-compile-check"),
)
.output()
.expect("run cargo check");
assert!(
output.status.success(),
"generated client failed to compile:\n{}",
String::from_utf8_lossy(&output.stderr)
);
}