use std::collections::BTreeSet;
use cratestack_core::Schema;
use cratestack_core::route_naming::to_snake_case;
use crate::diagnostics::{SchemaError, span_error};
use crate::validate::collect::record;
use crate::validate::query_attributes::validate_query_attributes;
use crate::validate::query_placeholders::validate_query_placeholders;
use crate::validate::query_signature::{validate_query_args, validate_query_result_type};
use crate::validate::reserved_idents::validate_reserved_identifier;
use crate::validate::snake_case_collisions::find_collision_by;
pub(super) fn validate_queries_collecting(
schema: &Schema,
type_names: &BTreeSet<String>,
errors: &mut Vec<SchemaError>,
) {
record(errors, || validate_unique_query_names(schema));
record(errors, || validate_query_module_collisions(schema));
record(errors, || validate_no_queries_under_datasource_none(schema));
for query in &schema.queries {
record(errors, || {
validate_reserved_identifier(
&query.name,
query.name_span,
&format!("query `{}`", query.name),
)
});
record(errors, || validate_query_attributes(query));
record(errors, || validate_query_args(query));
record(errors, || {
validate_query_result_type(query, schema, type_names)
});
record(errors, || validate_query_placeholders(query));
}
}
fn validate_unique_query_names(schema: &Schema) -> Result<(), SchemaError> {
let mut seen = BTreeSet::new();
for query in &schema.queries {
if !seen.insert(query.name.as_str()) {
return Err(span_error(
format!("duplicate query name `{}`", query.name),
query.span,
));
}
}
Ok(())
}
fn validate_query_module_collisions(schema: &Schema) -> Result<(), SchemaError> {
let entries = schema
.queries
.iter()
.map(|query| (query.name.as_str(), query.span));
match find_collision_by(entries, to_snake_case) {
Some((first, second, span, normalized)) => Err(span_error(
format!(
"queries `{first}` and `{second}` both generate the module `{normalized}` — \
rename one so each query has its own generated module"
),
span,
)),
None => Ok(()),
}
}
fn validate_no_queries_under_datasource_none(schema: &Schema) -> Result<(), SchemaError> {
if super::datasource_provider(schema) != Some("none") {
return Ok(());
}
match schema.queries.first() {
Some(query) => Err(span_error(
format!(
"query `{}` is not allowed: schema declares `datasource {{ provider = \"none\" }}`, \
which configures no database for a `query` to run against",
query.name
),
query.span,
)),
None => Ok(()),
}
}