use std::collections::{BTreeMap, BTreeSet}; use std::result::Result as StdResult; use std::str::FromStr; use once_cell::sync::Lazy; use regex::Regex; use serde::{Deserialize, Deserializer, Serialize}; #[derive(Default, Clone, Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Settings { #[serde(default, deserialize_with = "deserialize_some")] pub ranking_rules: Option>>, #[serde(default, deserialize_with = "deserialize_some")] pub distinct_attribute: Option>, #[serde(default, deserialize_with = "deserialize_some")] pub searchable_attributes: Option>>, #[serde(default, deserialize_with = "deserialize_some")] pub displayed_attributes: Option>>, #[serde(default, deserialize_with = "deserialize_some")] pub stop_words: Option>>, #[serde(default, deserialize_with = "deserialize_some")] pub synonyms: Option>>>, #[serde(default, deserialize_with = "deserialize_some")] pub attributes_for_faceting: Option>>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SettingsUpdate { pub ranking_rules: UpdateState>, pub distinct_attribute: UpdateState, pub primary_key: UpdateState, pub searchable_attributes: UpdateState>, pub displayed_attributes: UpdateState>, pub stop_words: UpdateState>, pub synonyms: UpdateState>>, pub attributes_for_faceting: UpdateState>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum UpdateState { Update(T), Clear, Nothing, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum RankingRule { Typo, Words, Proximity, Attribute, WordsPosition, Exactness, Asc(String), Desc(String), } static ASC_DESC_REGEX: Lazy = Lazy::new(|| Regex::new(r#"(asc|desc)\(([\w_-]+)\)"#).unwrap()); impl FromStr for RankingRule { type Err = (); fn from_str(s: &str) -> Result { Ok(match s { "typo" => Self::Typo, "words" => Self::Words, "proximity" => Self::Proximity, "attribute" => Self::Attribute, "wordsPosition" => Self::WordsPosition, "exactness" => Self::Exactness, text => { let caps = ASC_DESC_REGEX.captures(text).ok_or(())?; let order = caps.get(1).unwrap().as_str(); let field_name = caps.get(2).unwrap().as_str(); match order { "asc" => Self::Asc(field_name.to_string()), "desc" => Self::Desc(field_name.to_string()), _ => return Err(()), } } }) } } // Any value that is present is considered Some value, including null. fn deserialize_some<'de, T, D>(deserializer: D) -> StdResult, D::Error> where T: Deserialize<'de>, D: Deserializer<'de>, { Deserialize::deserialize(deserializer).map(Some) }