Check validity of settings with jayson in a more convenient way

This commit is contained in:
Loïc Lecrenier 2022-06-22 17:04:05 +02:00
parent 594f56ffe0
commit b014bab716
2 changed files with 63 additions and 7 deletions

View File

@ -8,6 +8,7 @@ use milli::update::{
use milli::Criterion; use milli::Criterion;
use serde::{Deserialize, Serialize, Serializer}; use serde::{Deserialize, Serialize, Serializer};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::convert::Infallible;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use uuid::Uuid; use uuid::Uuid;
@ -94,7 +95,7 @@ pub struct PaginationSettings {
#[derive( #[derive(
Debug, Clone, Default, Serialize, Deserialize, PartialEq, jayson::DeserializeFromValue, Debug, Clone, Default, Serialize, Deserialize, PartialEq, jayson::DeserializeFromValue,
)] )]
#[jayson(rename_all = camelCase, deny_unknown_fields)] #[jayson(rename_all = camelCase, deny_unknown_fields, validate = check_settings -> Infallible)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))] #[cfg_attr(test, derive(proptest_derive::Arbitrary))]
@ -105,7 +106,6 @@ pub struct Settings {
skip_serializing_if = "Setting::is_not_set" skip_serializing_if = "Setting::is_not_set"
)] )]
#[cfg_attr(test, proptest(strategy = "test::setting_strategy()"))] #[cfg_attr(test, proptest(strategy = "test::setting_strategy()"))]
#[jayson(map = map_searchable_or_displayed_attributes)]
pub displayed_attributes: Setting<Vec<String>>, pub displayed_attributes: Setting<Vec<String>>,
#[serde( #[serde(
@ -114,7 +114,6 @@ pub struct Settings {
skip_serializing_if = "Setting::is_not_set" skip_serializing_if = "Setting::is_not_set"
)] )]
#[cfg_attr(test, proptest(strategy = "test::setting_strategy()"))] #[cfg_attr(test, proptest(strategy = "test::setting_strategy()"))]
#[jayson(map = map_searchable_or_displayed_attributes)]
pub searchable_attributes: Setting<Vec<String>>, pub searchable_attributes: Setting<Vec<String>>,
#[serde(default, skip_serializing_if = "Setting::is_not_set")] #[serde(default, skip_serializing_if = "Setting::is_not_set")]
@ -164,8 +163,22 @@ impl Settings {
} }
} }
} }
fn map_searchable_or_displayed_attributes(setting: Setting<Vec<String>>) -> Setting<Vec<String>> { fn check_settings(settings: Settings) -> std::result::Result<Settings, Infallible> {
match setting { let Settings {
displayed_attributes,
searchable_attributes,
filterable_attributes,
sortable_attributes,
ranking_rules,
stop_words,
synonyms,
distinct_attribute,
typo_tolerance,
faceting,
pagination,
} = settings;
let displayed_attributes = match displayed_attributes {
Setting::Set(fields) => { Setting::Set(fields) => {
if fields.iter().any(|f| f == "*") { if fields.iter().any(|f| f == "*") {
Setting::Reset Setting::Reset
@ -174,7 +187,32 @@ fn map_searchable_or_displayed_attributes(setting: Setting<Vec<String>>) -> Sett
} }
} }
otherwise => otherwise, otherwise => otherwise,
};
let searchable_attributes = match searchable_attributes {
Setting::Set(fields) => {
if fields.iter().any(|f| f == "*") {
Setting::Reset
} else {
Setting::Set(fields)
} }
}
otherwise => otherwise,
};
Ok(Settings {
displayed_attributes,
searchable_attributes,
filterable_attributes,
sortable_attributes,
ranking_rules,
stop_words,
synonyms,
distinct_attribute,
typo_tolerance,
faceting,
pagination,
})
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -477,5 +515,14 @@ pub(crate) mod test {
}); });
let settings: Settings = jayson::deserialize::<_, _, MeiliDeserError>(j).unwrap(); let settings: Settings = jayson::deserialize::<_, _, MeiliDeserError>(j).unwrap();
assert_eq!(settings.displayed_attributes, Setting::Reset); assert_eq!(settings.displayed_attributes, Setting::Reset);
let j = json!({
"filterableAttributes": ["*"],
});
let settings: Settings = jayson::deserialize::<_, _, MeiliDeserError>(j).unwrap();
assert_eq!(
settings.filterable_attributes,
Setting::Set([String::from("*")].into_iter().collect())
);
} }
} }

View File

@ -1,4 +1,4 @@
use std::fmt; use std::{convert::Infallible, fmt};
use actix_web::{self as aweb, http::StatusCode, HttpResponseBuilder}; use actix_web::{self as aweb, http::StatusCode, HttpResponseBuilder};
use jayson::{ValueKind, ValuePointerRef}; use jayson::{ValueKind, ValuePointerRef};
@ -36,6 +36,15 @@ impl ErrorCode for MeiliDeserError {
Code::MalformedPayload Code::MalformedPayload
} }
} }
impl jayson::MergeWithError<Infallible> for MeiliDeserError {
fn merge(
_self_: Option<Self>,
_other: Infallible,
_merge_location: jayson::ValuePointerRef,
) -> Result<Self, Self> {
unreachable!()
}
}
impl jayson::MergeWithError<milli::CriterionError> for MeiliDeserError { impl jayson::MergeWithError<milli::CriterionError> for MeiliDeserError {
fn merge( fn merge(
_self_: Option<Self>, _self_: Option<Self>,