hide fields not in the displayedAttributes list from errors

This commit is contained in:
Vivek Kumar 2023-07-24 14:50:07 +05:30
parent 3dda93d50f
commit dd57873f8e
No known key found for this signature in database
GPG Key ID: 5F915FFA1FD3B841
4 changed files with 59 additions and 31 deletions

View File

@ -122,22 +122,28 @@ only composed of alphanumeric characters (a-z A-Z 0-9), hyphens (-) and undersco
.field, .field,
match .valid_fields.is_empty() { match .valid_fields.is_empty() {
true => "This index does not have configured sortable attributes.".to_string(), true => "This index does not have configured sortable attributes.".to_string(),
false => format!("Available sortable attributes are: `{}`.", false => format!("Available sortable attributes are: `{}{}`.",
valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", ") valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", "),
.hidden_fields.then_some(", <..hidden-attributes>").unwrap_or(""),
), ),
} }
)] )]
InvalidSortableAttribute { field: String, valid_fields: BTreeSet<String> }, InvalidSortableAttribute { field: String, valid_fields: BTreeSet<String>, hidden_fields: bool },
#[error("Attribute `{}` is not facet-searchable. {}", #[error("Attribute `{}` is not facet-searchable. {}",
.field, .field,
match .valid_fields.is_empty() { match .valid_fields.is_empty() {
true => "This index does not have configured facet-searchable attributes. To make it facet-searchable add it to the `filterableAttributes` index settings.".to_string(), true => "This index does not have configured facet-searchable attributes. To make it facet-searchable add it to the `filterableAttributes` index settings.".to_string(),
false => format!("Available facet-searchable attributes are: `{}`. To make it facet-searchable add it to the `filterableAttributes` index settings.", false => format!("Available facet-searchable attributes are: `{}{}`. To make it facet-searchable add it to the `filterableAttributes` index settings.",
valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", ") valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", "),
.hidden_fields.then_some(", <..hidden-attributes>").unwrap_or(""),
), ),
} }
)] )]
InvalidFacetSearchFacetName { field: String, valid_fields: BTreeSet<String> }, InvalidFacetSearchFacetName {
field: String,
valid_fields: BTreeSet<String>,
hidden_fields: bool,
},
#[error("Attribute `{}` is not searchable. Available searchable attributes are: `{}{}`.", #[error("Attribute `{}` is not searchable. Available searchable attributes are: `{}{}`.",
.field, .field,
.valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", "), .valid_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(", "),
@ -340,8 +346,11 @@ fn conditionally_lookup_for_error_message() {
]; ];
for (list, suffix) in messages { for (list, suffix) in messages {
let err = let err = UserError::InvalidSortableAttribute {
UserError::InvalidSortableAttribute { field: "name".to_string(), valid_fields: list }; field: "name".to_string(),
valid_fields: list,
hidden_fields: false,
};
assert_eq!(err.to_string(), format!("{} {}", prefix, suffix)); assert_eq!(err.to_string(), format!("{} {}", prefix, suffix));
} }

View File

@ -651,6 +651,26 @@ impl Index {
} }
} }
/* remove hidden fields */
pub fn remove_hidden_fields(
&self,
rtxn: &RoTxn,
fields: impl IntoIterator<Item = impl AsRef<str>>,
) -> Result<(BTreeSet<String>, bool)> {
let mut valid_fields =
fields.into_iter().map(|f| f.as_ref().to_string()).collect::<BTreeSet<String>>();
let fields_len = valid_fields.len();
if let Some(dn) = self.displayed_fields(rtxn)? {
let displayable_names = dn.iter().map(|s| s.to_string()).collect();
valid_fields = &valid_fields & &displayable_names;
}
let hidden_fields = fields_len > valid_fields.len();
Ok((valid_fields, hidden_fields))
}
/* searchable fields */ /* searchable fields */
/// Write the user defined searchable fields and generate the real searchable fields from the specified fields ids map. /// Write the user defined searchable fields and generate the real searchable fields from the specified fields ids map.

View File

@ -280,9 +280,13 @@ impl<'a> SearchForFacetValues<'a> {
let filterable_fields = index.filterable_fields(rtxn)?; let filterable_fields = index.filterable_fields(rtxn)?;
if !filterable_fields.contains(&self.facet) { if !filterable_fields.contains(&self.facet) {
let (valid_fields, hidden_fields) =
index.remove_hidden_fields(rtxn, filterable_fields)?;
return Err(UserError::InvalidFacetSearchFacetName { return Err(UserError::InvalidFacetSearchFacetName {
field: self.facet.clone(), field: self.facet.clone(),
valid_fields: filterable_fields.into_iter().collect(), valid_fields,
hidden_fields,
} }
.into()); .into());
} }

View File

@ -20,7 +20,7 @@ mod sort;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use std::collections::{BTreeSet, HashSet}; use std::collections::HashSet;
use bucket_sort::{bucket_sort, BucketSortOutput}; use bucket_sort::{bucket_sort, BucketSortOutput};
use charabia::TokenizerBuilder; use charabia::TokenizerBuilder;
@ -108,24 +108,11 @@ impl<'ctx> SearchContext<'ctx> {
(None, None) => continue, (None, None) => continue,
// The field is not searchable => User error // The field is not searchable => User error
(_fid, Some(false)) => { (_fid, Some(false)) => {
let mut valid_fields: BTreeSet<_> = let (valid_fields, hidden_fields) = match searchable_names {
fids_map.names().map(String::from).collect(); Some(sn) => self.index.remove_hidden_fields(self.txn, sn)?,
None => self.index.remove_hidden_fields(self.txn, fids_map.names())?,
};
// Filter by the searchable names
if let Some(sn) = searchable_names {
let searchable_names = sn.iter().map(|s| s.to_string()).collect();
valid_fields = &valid_fields & &searchable_names;
}
let searchable_count = valid_fields.len();
// Remove hidden fields
if let Some(dn) = self.index.displayed_fields(self.txn)? {
let displayable_names = dn.iter().map(|s| s.to_string()).collect();
valid_fields = &valid_fields & &displayable_names;
}
let hidden_fields = searchable_count > valid_fields.len();
let field = field_name.to_string(); let field = field_name.to_string();
return Err(UserError::InvalidSearchableAttribute { return Err(UserError::InvalidSearchableAttribute {
field, field,
@ -590,16 +577,24 @@ fn check_sort_criteria(ctx: &SearchContext, sort_criteria: Option<&Vec<AscDesc>>
for asc_desc in sort_criteria { for asc_desc in sort_criteria {
match asc_desc.member() { match asc_desc.member() {
Member::Field(ref field) if !crate::is_faceted(field, &sortable_fields) => { Member::Field(ref field) if !crate::is_faceted(field, &sortable_fields) => {
let (valid_fields, hidden_fields) =
ctx.index.remove_hidden_fields(ctx.txn, sortable_fields)?;
return Err(UserError::InvalidSortableAttribute { return Err(UserError::InvalidSortableAttribute {
field: field.to_string(), field: field.to_string(),
valid_fields: sortable_fields.into_iter().collect(), valid_fields,
})? hidden_fields,
})?;
} }
Member::Geo(_) if !sortable_fields.contains("_geo") => { Member::Geo(_) if !sortable_fields.contains("_geo") => {
let (valid_fields, hidden_fields) =
ctx.index.remove_hidden_fields(ctx.txn, sortable_fields)?;
return Err(UserError::InvalidSortableAttribute { return Err(UserError::InvalidSortableAttribute {
field: "_geo".to_string(), field: "_geo".to_string(),
valid_fields: sortable_fields.into_iter().collect(), valid_fields,
})? hidden_fields,
})?;
} }
_ => (), _ => (),
} }