diff --git a/milli/src/error.rs b/milli/src/error.rs index 8734cb540..87cb3f360 100644 --- a/milli/src/error.rs +++ b/milli/src/error.rs @@ -1,5 +1,6 @@ use std::collections::BTreeSet; use std::convert::Infallible; +use std::fmt::Write; use std::{io, str}; use heed::{Error as HeedError, MdbError}; @@ -100,10 +101,11 @@ A document identifier can be of type integer or string, \ only composed of alphanumeric characters (a-z A-Z 0-9), hyphens (-) and underscores (_).", .document_id.to_string() )] InvalidDocumentId { document_id: Value }, - #[error("Invalid facet distribution, the fields `{}` are not set as filterable.", - .invalid_facets_name.iter().map(AsRef::as_ref).collect::>().join(", ") - )] - InvalidFacetsDistribution { invalid_facets_name: BTreeSet }, + #[error("Invalid facet distribution, {}", format_invalid_filter_distribution(.invalid_facets_name, .valid_facets_name))] + InvalidFacetsDistribution { + invalid_facets_name: BTreeSet, + valid_facets_name: BTreeSet, + }, #[error(transparent)] InvalidGeoField(#[from] GeoError), #[error("{0}")] @@ -166,6 +168,50 @@ pub enum GeoError { BadLongitude { document_id: Value, value: Value }, } +fn format_invalid_filter_distribution( + invalid_facets_name: &BTreeSet, + valid_facets_name: &BTreeSet, +) -> String { + if valid_facets_name.is_empty() { + return "this index does not have configured filterable attributes.".into(); + } + + let mut result = String::new(); + + match invalid_facets_name.len() { + 0 => (), + 1 => write!( + result, + "attribute `{}` is not filterable.", + invalid_facets_name.first().unwrap() + ) + .unwrap(), + _ => write!( + result, + "attributes `{}` are not filterable.", + invalid_facets_name.iter().map(AsRef::as_ref).collect::>().join(", ") + ) + .unwrap(), + }; + + match valid_facets_name.len() { + 1 => write!( + result, + " The available filterable attribute is `{}`.", + valid_facets_name.first().unwrap() + ) + .unwrap(), + _ => write!( + result, + " The available filterable attributes are `{}`.", + valid_facets_name.iter().map(AsRef::as_ref).collect::>().join(", ") + ) + .unwrap(), + } + + result +} + /// A little macro helper to autogenerate From implementation that needs two `Into`. /// Given the following parameters: `error_from_sub_error!(FieldIdMapMissingEntry => InternalError)` /// the macro will create the following code: diff --git a/milli/src/search/facet/facet_distribution.rs b/milli/src/search/facet/facet_distribution.rs index 43367abbb..4d5028ce0 100644 --- a/milli/src/search/facet/facet_distribution.rs +++ b/milli/src/search/facet/facet_distribution.rs @@ -291,6 +291,7 @@ impl<'a> FacetDistribution<'a> { if !invalid_fields.is_empty() { return Err(UserError::InvalidFacetsDistribution { invalid_facets_name: invalid_fields.into_iter().cloned().collect(), + valid_facets_name: filterable_fields.into_iter().collect(), } .into()); } else {