Skip to content

Commit b926f13

Browse files
committed
Add filterableAttributes syntax API to settings
1 parent e90a3c2 commit b926f13

File tree

3 files changed

+135
-9
lines changed

3 files changed

+135
-9
lines changed

.code-samples.meilisearch.yaml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,14 +546,30 @@ get_filterable_attributes_1: |-
546546
.await
547547
.unwrap();
548548
update_filterable_attributes_1: |-
549-
let filterable_attributes = [
550-
"genres",
551-
"director"
549+
use meilisearch_sdk::settings::{
550+
FilterableAttribute,
551+
FilterableAttributesSettings,
552+
FilterFeatures,
553+
FilterFeatureModes,
554+
};
555+
556+
// Mixed legacy + new syntax
557+
let filterable_attributes: Vec<FilterableAttribute> = vec![
558+
// legacy: plain attribute name
559+
"author".into(),
560+
// new syntax: settings object
561+
FilterableAttribute::Settings(FilterableAttributesSettings {
562+
attribute_patterns: vec!["genre".to_string()],
563+
features: FilterFeatures {
564+
facet_search: true,
565+
filter: FilterFeatureModes { equality: true, comparison: false },
566+
},
567+
}),
552568
];
553569
554570
let task: TaskInfo = client
555571
.index("movies")
556-
.set_filterable_attributes(&filterable_attributes)
572+
.set_filterable_attributes_advanced(&filterable_attributes)
557573
.await
558574
.unwrap();
559575
reset_filterable_attributes_1: |-

src/documents.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,9 +703,13 @@ Hint: It might not be working because you're not up to date with the Meilisearch
703703
);
704704
assert!(video_settings.displayed_attributes.unwrap().is_empty());
705705

706+
use crate::settings::FilterableAttribute;
706707
assert_eq!(
707708
movie_settings.filterable_attributes.unwrap(),
708-
["release_date", "genres"]
709+
vec![
710+
FilterableAttribute::Attribute("release_date".to_string()),
711+
FilterableAttribute::Attribute("genres".to_string()),
712+
]
709713
);
710714
assert!(video_settings.filterable_attributes.unwrap().is_empty());
711715

src/settings.rs

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,55 @@ pub struct FacetingSettings {
6464
pub sort_facet_values_by: Option<BTreeMap<String, FacetSortValue>>,
6565
}
6666

67+
/// Filterable attribute settings.
68+
///
69+
/// Meilisearch supports a mixed syntax: either a plain attribute name
70+
/// (string) or an object describing patterns and feature flags. This SDK
71+
/// models it with `FilterableAttribute` (untagged enum) and associated
72+
/// settings structs.
73+
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
74+
#[serde(rename_all = "camelCase")]
75+
pub struct FilterFeatureModes {
76+
pub equality: bool,
77+
pub comparison: bool,
78+
}
79+
80+
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
81+
#[serde(rename_all = "camelCase")]
82+
pub struct FilterFeatures {
83+
pub facet_search: bool,
84+
pub filter: FilterFeatureModes,
85+
}
86+
87+
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
88+
#[serde(rename_all = "camelCase")]
89+
pub struct FilterableAttributesSettings {
90+
#[serde(rename = "attributePatterns")]
91+
pub attribute_patterns: Vec<String>,
92+
pub features: FilterFeatures,
93+
}
94+
95+
/// A filterable attribute definition, either a plain attribute name or a
96+
/// settings object.
97+
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
98+
#[serde(untagged)]
99+
pub enum FilterableAttribute {
100+
Attribute(String),
101+
Settings(FilterableAttributesSettings),
102+
}
103+
104+
impl From<String> for FilterableAttribute {
105+
fn from(value: String) -> Self {
106+
FilterableAttribute::Attribute(value)
107+
}
108+
}
109+
110+
impl From<&str> for FilterableAttribute {
111+
fn from(value: &str) -> Self {
112+
FilterableAttribute::Attribute(value.to_string())
113+
}
114+
}
115+
67116
#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
68117
#[serde(rename_all = "camelCase")]
69118
pub enum EmbedderSource {
@@ -193,8 +242,10 @@ pub struct Settings {
193242
#[serde(skip_serializing_if = "Option::is_none")]
194243
pub ranking_rules: Option<Vec<String>>,
195244
/// Attributes to use for [filtering](https://www.meilisearch.com/docs/learn/advanced/filtering).
245+
///
246+
/// Supports both plain attribute names and settings objects.
196247
#[serde(skip_serializing_if = "Option::is_none")]
197-
pub filterable_attributes: Option<Vec<String>>,
248+
pub filterable_attributes: Option<Vec<FilterableAttribute>>,
198249
/// Attributes to sort.
199250
#[serde(skip_serializing_if = "Option::is_none")]
200251
pub sortable_attributes: Option<Vec<String>>,
@@ -324,16 +375,29 @@ impl Settings {
324375
filterable_attributes: impl IntoIterator<Item = impl AsRef<str>>,
325376
) -> Settings {
326377
Settings {
378+
// Legacy helper accepting a list of attribute names.
327379
filterable_attributes: Some(
328380
filterable_attributes
329381
.into_iter()
330-
.map(|v| v.as_ref().to_string())
382+
.map(|v| FilterableAttribute::Attribute(v.as_ref().to_string()))
331383
.collect(),
332384
),
333385
..self
334386
}
335387
}
336388

389+
/// Set filterable attributes using mixed syntax.
390+
#[must_use]
391+
pub fn with_filterable_attributes_advanced(
392+
self,
393+
filterable_attributes: impl IntoIterator<Item = FilterableAttribute>,
394+
) -> Settings {
395+
Settings {
396+
filterable_attributes: Some(filterable_attributes.into_iter().collect()),
397+
..self
398+
}
399+
}
400+
337401
#[must_use]
338402
pub fn with_sortable_attributes(
339403
self,
@@ -714,6 +778,26 @@ impl<Http: HttpClient> Index<Http> {
714778
.await
715779
}
716780

781+
/// Get filterable attributes using mixed syntax.
782+
///
783+
/// Returns a list that can contain plain attribute names (strings) and/or
784+
/// settings objects.
785+
pub async fn get_filterable_attributes_advanced(
786+
&self,
787+
) -> Result<Vec<FilterableAttribute>, Error> {
788+
self.client
789+
.http_client
790+
.request::<(), (), Vec<FilterableAttribute>>(
791+
&format!(
792+
"{}/indexes/{}/settings/filterable-attributes",
793+
self.client.host, self.uid
794+
),
795+
Method::Get { query: () },
796+
200,
797+
)
798+
.await
799+
}
800+
717801
/// Get [sortable attributes](https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes) of the [Index].
718802
///
719803
/// # Example
@@ -1507,9 +1591,10 @@ impl<Http: HttpClient> Index<Http> {
15071591
&self,
15081592
filterable_attributes: impl IntoIterator<Item = impl AsRef<str>>,
15091593
) -> Result<TaskInfo, Error> {
1594+
// Backward-compatible helper: accept a list of attribute names.
15101595
self.client
15111596
.http_client
1512-
.request::<(), Vec<String>, TaskInfo>(
1597+
.request::<(), Vec<FilterableAttribute>, TaskInfo>(
15131598
&format!(
15141599
"{}/indexes/{}/settings/filterable-attributes",
15151600
self.client.host, self.uid
@@ -1518,14 +1603,35 @@ impl<Http: HttpClient> Index<Http> {
15181603
query: (),
15191604
body: filterable_attributes
15201605
.into_iter()
1521-
.map(|v| v.as_ref().to_string())
1606+
.map(|v| FilterableAttribute::Attribute(v.as_ref().to_string()))
15221607
.collect(),
15231608
},
15241609
202,
15251610
)
15261611
.await
15271612
}
15281613

1614+
/// Update filterable attributes using mixed syntax.
1615+
pub async fn set_filterable_attributes_advanced(
1616+
&self,
1617+
filterable_attributes: impl IntoIterator<Item = FilterableAttribute>,
1618+
) -> Result<TaskInfo, Error> {
1619+
self.client
1620+
.http_client
1621+
.request::<(), Vec<FilterableAttribute>, TaskInfo>(
1622+
&format!(
1623+
"{}/indexes/{}/settings/filterable-attributes",
1624+
self.client.host, self.uid
1625+
),
1626+
Method::Put {
1627+
query: (),
1628+
body: filterable_attributes.into_iter().collect(),
1629+
},
1630+
202,
1631+
)
1632+
.await
1633+
}
1634+
15291635
/// Update [sortable attributes](https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes) of the [Index].
15301636
///
15311637
/// # Example

0 commit comments

Comments
 (0)