use std::collections::BTreeSet;
use cratestack_core::{Attribute, Model, parse_index_attribute};
use crate::diagnostics::{SchemaError, span_error};
use super::composite_attributes::resolve_scalar_field;
pub(super) type SeenIndexAttributes = Vec<(Vec<String>, Option<String>)>;
pub(super) fn validate_index_attribute(
model: &Model,
attribute: &Attribute,
model_names: &BTreeSet<&str>,
seen: &mut SeenIndexAttributes,
) -> Result<(), SchemaError> {
if !attribute.raw.starts_with("@@index(") {
return Err(span_error(
format!(
"model `{}` `@@index` requires a field list: `@@index([field1, field2])`",
model.name,
),
attribute.span,
));
}
let parsed = parse_index_attribute(&attribute.raw)
.map_err(|message| span_error(message, attribute.span))?;
for field_name in &parsed.fields {
resolve_scalar_field(model, attribute, model_names, field_name, "@@index([...])")?;
}
let key = (parsed.fields.clone(), parsed.using.clone());
if seen.contains(&key) {
let using_suffix = parsed
.using
.as_deref()
.map(|using| format!(", using: {using}"))
.unwrap_or_default();
return Err(span_error(
format!(
"model `{}` declares the same `@@index([{}]{using_suffix})` constraint more than once",
model.name,
parsed.fields.join(", "),
),
attribute.span,
));
}
seen.push(key);
Ok(())
}