use proc_macro::TokenStream;
use syn::LitStr;
use super::parse::ServerDb;
pub(super) fn guard_server_datasource_provider(
schema_path: &LitStr,
schema: &cratestack_core::Schema,
db: ServerDb,
) -> Result<(), TokenStream> {
let Some(provider) = schema_datasource_provider(schema) else {
return Ok(());
};
let expected_provider = match db {
ServerDb::Postgres => "postgresql",
ServerDb::None => "none",
};
if provider == expected_provider {
return Ok(());
}
let db_arg = match db {
ServerDb::Postgres => "Postgres",
ServerDb::None => "None",
};
Err(TokenStream::from(
syn::Error::new(
schema_path.span(),
format!(
"include_server_schema!(..., db = {db_arg}) requires this schema's `datasource \
{{ provider = \"...\" }}` to be `\"{expected_provider}\"`, but found \
`\"{provider}\"` — the macro's `db` argument and the schema's own `datasource` \
declaration must agree. Either change `db = {db_arg}` to match the schema, or \
change the schema's `provider` to `\"{expected_provider}\"` (see \
https://github.com/cratestack/cratestack/issues/327)."
),
)
.to_compile_error(),
))
}
fn schema_datasource_provider(schema: &cratestack_core::Schema) -> Option<&str> {
schema
.datasource
.as_ref()?
.entries
.iter()
.find(|entry| entry.key == "provider")
.map(|entry| entry.value.trim_matches('"'))
}
#[cfg(test)]
mod tests {
use super::{ServerDb, schema_datasource_provider};
#[test]
fn reads_provider_from_datasource_block() {
let schema = cratestack_parser::parse_schema(
r#"
datasource db {
provider = "postgresql"
}
model Widget {
id Int @id
}
"#,
)
.expect("schema should parse");
assert_eq!(schema_datasource_provider(&schema), Some("postgresql"));
}
#[test]
fn reads_none_provider_from_datasource_block() {
let schema = cratestack_parser::parse_schema(
r#"
datasource db {
provider = "none"
}
"#,
)
.expect("schema should parse");
assert_eq!(schema_datasource_provider(&schema), Some("none"));
}
#[test]
fn no_datasource_block_yields_no_provider() {
let schema = cratestack_parser::parse_schema(
r#"
model Widget {
id Int @id
}
"#,
)
.expect("schema should parse");
assert_eq!(schema_datasource_provider(&schema), None);
}
#[test]
fn server_db_variants_are_distinct() {
assert_ne!(ServerDb::Postgres, ServerDb::None);
}
}