From 68c4717e215d12da34789d3e49e5d7223468fc4f Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 28 Nov 2024 11:34:35 +0100 Subject: [PATCH 1/4] Change the settings tests and macros to avoid oversights --- .../src/routes/indexes/settings.rs | 514 ++++++++---------- .../tests/settings/get_settings.rs | 35 +- 2 files changed, 274 insertions(+), 275 deletions(-) diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index e1794535b..e08047d83 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -17,6 +17,26 @@ use crate::extractors::authentication::GuardedData; use crate::routes::{get_task_id, is_dry_run, SummarizedTaskView}; use crate::Opt; +macro_rules! make_setting_routes { + ($({$route:literal, $update_verb:ident, $type:ty, $err_ty:ty, $attr:ident, $camelcase_attr:literal, $analytics:ident}),*) => { + $( + make_setting_route!($route, $update_verb, $type, $err_ty, $attr, $camelcase_attr, $analytics); + )* + + pub fn configure(cfg: &mut web::ServiceConfig) { + use crate::extractors::sequential_extractor::SeqHandler; + cfg.service( + web::resource("") + .route(web::patch().to(SeqHandler(update_all))) + .route(web::get().to(SeqHandler(get_all))) + .route(web::delete().to(SeqHandler(delete_all)))) + $(.service($attr::resources()))*; + } + + pub const ALL_SETTINGS_NAMES: &[&str] = &[$(stringify!($attr)),*]; + }; +} + #[macro_export] macro_rules! make_setting_route { ($route:literal, $update_verb:ident, $type:ty, $err_ty:ty, $attr:ident, $camelcase_attr:literal, $analytics:ident) => { @@ -153,279 +173,227 @@ macro_rules! make_setting_route { }; } -make_setting_route!( - "/filterable-attributes", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsFilterableAttributes, - >, - filterable_attributes, - "filterableAttributes", - FilterableAttributesAnalytics -); - -make_setting_route!( - "/sortable-attributes", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsSortableAttributes, - >, - sortable_attributes, - "sortableAttributes", - SortableAttributesAnalytics -); - -make_setting_route!( - "/displayed-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsDisplayedAttributes, - >, - displayed_attributes, - "displayedAttributes", - DisplayedAttributesAnalytics -); - -make_setting_route!( - "/typo-tolerance", - patch, - meilisearch_types::settings::TypoSettings, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsTypoTolerance, - >, - typo_tolerance, - "typoTolerance", - TypoToleranceAnalytics -); - -make_setting_route!( - "/searchable-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsSearchableAttributes, - >, - searchable_attributes, - "searchableAttributes", - SearchableAttributesAnalytics -); - -make_setting_route!( - "/stop-words", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsStopWords, - >, - stop_words, - "stopWords", - StopWordsAnalytics -); - -make_setting_route!( - "/non-separator-tokens", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsNonSeparatorTokens, - >, - non_separator_tokens, - "nonSeparatorTokens", - NonSeparatorTokensAnalytics -); - -make_setting_route!( - "/separator-tokens", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsSeparatorTokens, - >, - separator_tokens, - "separatorTokens", - SeparatorTokensAnalytics -); - -make_setting_route!( - "/dictionary", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsDictionary, - >, - dictionary, - "dictionary", - DictionaryAnalytics -); - -make_setting_route!( - "/synonyms", - put, - std::collections::BTreeMap>, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsSynonyms, - >, - synonyms, - "synonyms", - SynonymsAnalytics -); - -make_setting_route!( - "/distinct-attribute", - put, - String, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsDistinctAttribute, - >, - distinct_attribute, - "distinctAttribute", - DistinctAttributeAnalytics -); - -make_setting_route!( - "/proximity-precision", - put, - meilisearch_types::settings::ProximityPrecisionView, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsProximityPrecision, - >, - proximity_precision, - "proximityPrecision", - ProximityPrecisionAnalytics -); - -make_setting_route!( - "/localized-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsLocalizedAttributes, - >, - localized_attributes, - "localizedAttributes", - LocalesAnalytics -); - -make_setting_route!( - "/ranking-rules", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsRankingRules, - >, - ranking_rules, - "rankingRules", - RankingRulesAnalytics -); - -make_setting_route!( - "/faceting", - patch, - meilisearch_types::settings::FacetingSettings, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsFaceting, - >, - faceting, - "faceting", - FacetingAnalytics -); - -make_setting_route!( - "/pagination", - patch, - meilisearch_types::settings::PaginationSettings, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsPagination, - >, - pagination, - "pagination", - PaginationAnalytics -); - -make_setting_route!( - "/embedders", - patch, - std::collections::BTreeMap>, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsEmbedders, - >, - embedders, - "embedders", - EmbeddersAnalytics -); - -make_setting_route!( - "/search-cutoff-ms", - put, - u64, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsSearchCutoffMs, - >, - search_cutoff_ms, - "searchCutoffMs", - SearchCutoffMsAnalytics -); - -make_setting_route!( - "/facet-search", - put, - bool, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsFacetSearch, - >, - facet_search, - "facetSearch", - FacetSearchAnalytics -); - -make_setting_route!( - "/prefix-search", - put, - meilisearch_types::settings::PrefixSearchSettings, - meilisearch_types::deserr::DeserrJsonError< - meilisearch_types::error::deserr_codes::InvalidSettingsPrefixSearch, - >, - prefix_search, - "prefixSearch", - PrefixSearchAnalytics -); - -macro_rules! generate_configure { - ($($mod:ident),*) => { - pub fn configure(cfg: &mut web::ServiceConfig) { - use crate::extractors::sequential_extractor::SeqHandler; - cfg.service( - web::resource("") - .route(web::patch().to(SeqHandler(update_all))) - .route(web::get().to(SeqHandler(get_all))) - .route(web::delete().to(SeqHandler(delete_all)))) - $(.service($mod::resources()))*; - } - }; -} - -generate_configure!( - filterable_attributes, - sortable_attributes, - displayed_attributes, - localized_attributes, - searchable_attributes, - distinct_attribute, - proximity_precision, - stop_words, - separator_tokens, - non_separator_tokens, - dictionary, - synonyms, - ranking_rules, - typo_tolerance, - pagination, - faceting, - embedders, - search_cutoff_ms +make_setting_routes!( + { + "/filterable-attributes", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsFilterableAttributes, + >, + filterable_attributes, + "filterableAttributes", + FilterableAttributesAnalytics + }, + { + "/sortable-attributes", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsSortableAttributes, + >, + sortable_attributes, + "sortableAttributes", + SortableAttributesAnalytics + }, + { + "/displayed-attributes", + put, + Vec, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsDisplayedAttributes, + >, + displayed_attributes, + "displayedAttributes", + DisplayedAttributesAnalytics + }, + { + "/typo-tolerance", + patch, + meilisearch_types::settings::TypoSettings, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsTypoTolerance, + >, + typo_tolerance, + "typoTolerance", + TypoToleranceAnalytics + }, + { + "/searchable-attributes", + put, + Vec, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsSearchableAttributes, + >, + searchable_attributes, + "searchableAttributes", + SearchableAttributesAnalytics + }, + { + "/stop-words", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsStopWords, + >, + stop_words, + "stopWords", + StopWordsAnalytics + }, + { + "/non-separator-tokens", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsNonSeparatorTokens, + >, + non_separator_tokens, + "nonSeparatorTokens", + NonSeparatorTokensAnalytics + }, + { + "/separator-tokens", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsSeparatorTokens, + >, + separator_tokens, + "separatorTokens", + SeparatorTokensAnalytics + }, + { + "/dictionary", + put, + std::collections::BTreeSet, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsDictionary, + >, + dictionary, + "dictionary", + DictionaryAnalytics + }, + { + "/synonyms", + put, + std::collections::BTreeMap>, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsSynonyms, + >, + synonyms, + "synonyms", + SynonymsAnalytics + }, + { + "/distinct-attribute", + put, + String, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsDistinctAttribute, + >, + distinct_attribute, + "distinctAttribute", + DistinctAttributeAnalytics + }, + { + "/proximity-precision", + put, + meilisearch_types::settings::ProximityPrecisionView, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsProximityPrecision, + >, + proximity_precision, + "proximityPrecision", + ProximityPrecisionAnalytics + }, + { + "/localized-attributes", + put, + Vec, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsLocalizedAttributes, + >, + localized_attributes, + "localizedAttributes", + LocalesAnalytics + }, + { + "/ranking-rules", + put, + Vec, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsRankingRules, + >, + ranking_rules, + "rankingRules", + RankingRulesAnalytics + }, + { + "/faceting", + patch, + meilisearch_types::settings::FacetingSettings, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsFaceting, + >, + faceting, + "faceting", + FacetingAnalytics + }, + { + "/pagination", + patch, + meilisearch_types::settings::PaginationSettings, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsPagination, + >, + pagination, + "pagination", + PaginationAnalytics + }, + { + "/embedders", + patch, + std::collections::BTreeMap>, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsEmbedders, + >, + embedders, + "embedders", + EmbeddersAnalytics + }, + { + "/search-cutoff-ms", + put, + u64, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsSearchCutoffMs, + >, + search_cutoff_ms, + "searchCutoffMs", + SearchCutoffMsAnalytics + }, + { + "/facet-search", + put, + bool, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsFacetSearch, + >, + facet_search, + "facetSearch", + FacetSearchAnalytics + }, + { + "/prefix-search", + put, + meilisearch_types::settings::PrefixSearchSettings, + meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsPrefixSearch, + >, + prefix_search, + "prefixSearch", + PrefixSearchAnalytics + } ); pub async fn update_all( diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index 1b1964680..bb1aa861d 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -37,6 +37,23 @@ static DEFAULT_SETTINGS_VALUES: Lazy> = Lazy::new(| }), ); map.insert("search_cutoff_ms", json!(null)); + map.insert("embedders", json!(null)); + map.insert("facet_search", json!(true)); + map.insert("prefix_search", json!("indexingTime")); + map.insert("proximity_precision", json!("byWord")); + map.insert("sortable_attributes", json!([])); + map.insert( + "typo_tolerance", + json!({ + "enabled": true, + "minWordSizeForTypos": { + "oneTypo": 5, + "twoTypos": 9 + }, + "disableOnWords": [], + "disableOnAttributes": [] + }), + ); map }); @@ -343,7 +360,7 @@ async fn error_update_setting_unexisting_index_invalid_uid() { } macro_rules! test_setting_routes { - ($($setting:ident $write_method:ident), *) => { + ($($setting:ident $write_method:ident,) *) => { $( mod $setting { use crate::common::Server; @@ -409,6 +426,14 @@ macro_rules! test_setting_routes { } } )* + + #[actix_rt::test] + async fn all_setting_tested() { + let expected = std::collections::BTreeSet::from_iter(meilisearch::routes::indexes::settings::ALL_SETTINGS_NAMES.iter()); + let tested = std::collections::BTreeSet::from_iter([$(stringify!($setting)),*].iter()); + let diff: Vec<_> = expected.difference(&tested).collect(); + assert!(diff.is_empty(), "Not all settings were tested, please add the following settings to the `test_setting_routes!` macro: {:?}", diff); + } }; } @@ -426,7 +451,13 @@ test_setting_routes!( synonyms put, pagination patch, faceting patch, - search_cutoff_ms put + search_cutoff_ms put, + embedders patch, + facet_search put, + prefix_search put, + proximity_precision put, + sortable_attributes put, + typo_tolerance patch, ); #[actix_rt::test] From 9f36ffcbdb2e09799987f9da93660b4ab27d2bcb Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 28 Nov 2024 11:44:09 +0100 Subject: [PATCH 2/4] Polish make_setting_routes! --- .../src/routes/indexes/settings.rs | 284 +++++++++--------- 1 file changed, 142 insertions(+), 142 deletions(-) diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index e08047d83..bb24fc880 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -18,7 +18,7 @@ use crate::routes::{get_task_id, is_dry_run, SummarizedTaskView}; use crate::Opt; macro_rules! make_setting_routes { - ($({$route:literal, $update_verb:ident, $type:ty, $err_ty:ty, $attr:ident, $camelcase_attr:literal, $analytics:ident}),*) => { + ($({route: $route:literal, update_verb: $update_verb:ident, value_type: $type:ty, err_type: $err_ty:ty, attr: $attr:ident, camelcase_attr: $camelcase_attr:literal, analytics: $analytics:ident},)*) => { $( make_setting_route!($route, $update_verb, $type, $err_ty, $attr, $camelcase_attr, $analytics); )* @@ -175,225 +175,225 @@ macro_rules! make_setting_route { make_setting_routes!( { - "/filterable-attributes", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/filterable-attributes", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsFilterableAttributes, >, - filterable_attributes, - "filterableAttributes", - FilterableAttributesAnalytics + attr: filterable_attributes, + camelcase_attr: "filterableAttributes", + analytics: FilterableAttributesAnalytics }, { - "/sortable-attributes", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/sortable-attributes", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSortableAttributes, >, - sortable_attributes, - "sortableAttributes", - SortableAttributesAnalytics + attr: sortable_attributes, + camelcase_attr: "sortableAttributes", + analytics: SortableAttributesAnalytics }, { - "/displayed-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< + route: "/displayed-attributes", + update_verb: put, + value_type: Vec, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsDisplayedAttributes, >, - displayed_attributes, - "displayedAttributes", - DisplayedAttributesAnalytics + attr: displayed_attributes, + camelcase_attr: "displayedAttributes", + analytics: DisplayedAttributesAnalytics }, { - "/typo-tolerance", - patch, - meilisearch_types::settings::TypoSettings, - meilisearch_types::deserr::DeserrJsonError< + route: "/typo-tolerance", + update_verb: patch, + value_type: meilisearch_types::settings::TypoSettings, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsTypoTolerance, >, - typo_tolerance, - "typoTolerance", - TypoToleranceAnalytics + attr: typo_tolerance, + camelcase_attr: "typoTolerance", + analytics: TypoToleranceAnalytics }, { - "/searchable-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< + route: "/searchable-attributes", + update_verb: put, + value_type: Vec, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSearchableAttributes, >, - searchable_attributes, - "searchableAttributes", - SearchableAttributesAnalytics + attr: searchable_attributes, + camelcase_attr: "searchableAttributes", + analytics: SearchableAttributesAnalytics }, { - "/stop-words", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/stop-words", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsStopWords, >, - stop_words, - "stopWords", - StopWordsAnalytics + attr: stop_words, + camelcase_attr: "stopWords", + analytics: StopWordsAnalytics }, { - "/non-separator-tokens", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/non-separator-tokens", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsNonSeparatorTokens, >, - non_separator_tokens, - "nonSeparatorTokens", - NonSeparatorTokensAnalytics + attr: non_separator_tokens, + camelcase_attr: "nonSeparatorTokens", + analytics: NonSeparatorTokensAnalytics }, { - "/separator-tokens", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/separator-tokens", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSeparatorTokens, >, - separator_tokens, - "separatorTokens", - SeparatorTokensAnalytics + attr: separator_tokens, + camelcase_attr: "separatorTokens", + analytics: SeparatorTokensAnalytics }, { - "/dictionary", - put, - std::collections::BTreeSet, - meilisearch_types::deserr::DeserrJsonError< + route: "/dictionary", + update_verb: put, + value_type: std::collections::BTreeSet, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsDictionary, >, - dictionary, - "dictionary", - DictionaryAnalytics + attr: dictionary, + camelcase_attr: "dictionary", + analytics: DictionaryAnalytics }, { - "/synonyms", - put, - std::collections::BTreeMap>, - meilisearch_types::deserr::DeserrJsonError< + route: "/synonyms", + update_verb: put, + value_type: std::collections::BTreeMap>, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSynonyms, >, - synonyms, - "synonyms", - SynonymsAnalytics + attr: synonyms, + camelcase_attr: "synonyms", + analytics: SynonymsAnalytics }, { - "/distinct-attribute", - put, - String, - meilisearch_types::deserr::DeserrJsonError< + route: "/distinct-attribute", + update_verb: put, + value_type: String, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsDistinctAttribute, >, - distinct_attribute, - "distinctAttribute", - DistinctAttributeAnalytics + attr: distinct_attribute, + camelcase_attr: "distinctAttribute", + analytics: DistinctAttributeAnalytics }, { - "/proximity-precision", - put, - meilisearch_types::settings::ProximityPrecisionView, - meilisearch_types::deserr::DeserrJsonError< + route: "/proximity-precision", + update_verb: put, + value_type: meilisearch_types::settings::ProximityPrecisionView, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsProximityPrecision, >, - proximity_precision, - "proximityPrecision", - ProximityPrecisionAnalytics + attr: proximity_precision, + camelcase_attr: "proximityPrecision", + analytics: ProximityPrecisionAnalytics }, { - "/localized-attributes", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< + route: "/localized-attributes", + update_verb: put, + value_type: Vec, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsLocalizedAttributes, >, - localized_attributes, - "localizedAttributes", - LocalesAnalytics + attr: localized_attributes, + camelcase_attr: "localizedAttributes", + analytics: LocalesAnalytics }, { - "/ranking-rules", - put, - Vec, - meilisearch_types::deserr::DeserrJsonError< + route: "/ranking-rules", + update_verb: put, + value_type: Vec, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsRankingRules, >, - ranking_rules, - "rankingRules", - RankingRulesAnalytics + attr: ranking_rules, + camelcase_attr: "rankingRules", + analytics: RankingRulesAnalytics }, { - "/faceting", - patch, - meilisearch_types::settings::FacetingSettings, - meilisearch_types::deserr::DeserrJsonError< + route: "/faceting", + update_verb: patch, + value_type: meilisearch_types::settings::FacetingSettings, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsFaceting, >, - faceting, - "faceting", - FacetingAnalytics + attr: faceting, + camelcase_attr: "faceting", + analytics: FacetingAnalytics }, { - "/pagination", - patch, - meilisearch_types::settings::PaginationSettings, - meilisearch_types::deserr::DeserrJsonError< + route: "/pagination", + update_verb: patch, + value_type: meilisearch_types::settings::PaginationSettings, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsPagination, >, - pagination, - "pagination", - PaginationAnalytics + attr: pagination, + camelcase_attr: "pagination", + analytics: PaginationAnalytics }, { - "/embedders", - patch, - std::collections::BTreeMap>, - meilisearch_types::deserr::DeserrJsonError< + route: "/embedders", + update_verb: patch, + value_type: std::collections::BTreeMap>, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsEmbedders, >, - embedders, - "embedders", - EmbeddersAnalytics + attr: embedders, + camelcase_attr: "embedders", + analytics: EmbeddersAnalytics }, { - "/search-cutoff-ms", - put, - u64, - meilisearch_types::deserr::DeserrJsonError< + route: "/search-cutoff-ms", + update_verb: put, + value_type: u64, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSearchCutoffMs, >, - search_cutoff_ms, - "searchCutoffMs", - SearchCutoffMsAnalytics + attr: search_cutoff_ms, + camelcase_attr: "searchCutoffMs", + analytics: SearchCutoffMsAnalytics }, { - "/facet-search", - put, - bool, - meilisearch_types::deserr::DeserrJsonError< + route: "/facet-search", + update_verb: put, + value_type: bool, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsFacetSearch, >, - facet_search, - "facetSearch", - FacetSearchAnalytics + attr: facet_search, + camelcase_attr: "facetSearch", + analytics: FacetSearchAnalytics }, { - "/prefix-search", - put, - meilisearch_types::settings::PrefixSearchSettings, - meilisearch_types::deserr::DeserrJsonError< + route: "/prefix-search", + update_verb: put, + value_type: meilisearch_types::settings::PrefixSearchSettings, + err_type: meilisearch_types::deserr::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsPrefixSearch, >, - prefix_search, - "prefixSearch", - PrefixSearchAnalytics - } + attr: prefix_search, + camelcase_attr: "prefixSearch", + analytics: PrefixSearchAnalytics + }, ); pub async fn update_all( From 5383f41bba83f522a43c993e6c6261042d430232 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 28 Nov 2024 11:55:38 +0100 Subject: [PATCH 3/4] Polish test_setting_routes! --- .../tests/settings/get_settings.rs | 187 ++++++++++-------- 1 file changed, 105 insertions(+), 82 deletions(-) diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index bb1aa861d..b9e10033a 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -1,62 +1,6 @@ -use std::collections::HashMap; - -use once_cell::sync::Lazy; - -use crate::common::{Server, Value}; +use crate::common::Server; use crate::json; -static DEFAULT_SETTINGS_VALUES: Lazy> = Lazy::new(|| { - let mut map = HashMap::new(); - map.insert("displayed_attributes", json!(["*"])); - map.insert("searchable_attributes", json!(["*"])); - map.insert("localized_attributes", json!(null)); - map.insert("filterable_attributes", json!([])); - map.insert("distinct_attribute", json!(null)); - map.insert( - "ranking_rules", - json!(["words", "typo", "proximity", "attribute", "sort", "exactness"]), - ); - map.insert("stop_words", json!([])); - map.insert("non_separator_tokens", json!([])); - map.insert("separator_tokens", json!([])); - map.insert("dictionary", json!([])); - map.insert("synonyms", json!({})); - map.insert( - "faceting", - json!({ - "maxValuesPerFacet": json!(100), - "sortFacetValuesBy": { - "*": "alpha" - } - }), - ); - map.insert( - "pagination", - json!({ - "maxTotalHits": json!(1000), - }), - ); - map.insert("search_cutoff_ms", json!(null)); - map.insert("embedders", json!(null)); - map.insert("facet_search", json!(true)); - map.insert("prefix_search", json!("indexingTime")); - map.insert("proximity_precision", json!("byWord")); - map.insert("sortable_attributes", json!([])); - map.insert( - "typo_tolerance", - json!({ - "enabled": true, - "minWordSizeForTypos": { - "oneTypo": 5, - "twoTypos": 9 - }, - "disableOnWords": [], - "disableOnAttributes": [] - }), - ); - map -}); - #[actix_rt::test] async fn get_settings_unexisting_index() { let server = Server::new().await; @@ -360,11 +304,10 @@ async fn error_update_setting_unexisting_index_invalid_uid() { } macro_rules! test_setting_routes { - ($($setting:ident $write_method:ident,) *) => { + ($({setting: $setting:ident, update_verb: $update_verb:ident, default_value: $default_value:tt},) *) => { $( mod $setting { use crate::common::Server; - use super::DEFAULT_SETTINGS_VALUES; #[actix_rt::test] async fn get_unexisting_index() { @@ -386,7 +329,7 @@ macro_rules! test_setting_routes { .chars() .map(|c| if c == '_' { '-' } else { c }) .collect::()); - let (response, code) = server.service.$write_method(url, serde_json::Value::Null.into()).await; + let (response, code) = server.service.$update_verb(url, serde_json::Value::Null.into()).await; assert_eq!(code, 202, "{}", response); server.index("").wait_task(0).await; let (response, code) = server.index("test").get().await; @@ -421,8 +364,8 @@ macro_rules! test_setting_routes { .collect::()); let (response, code) = server.service.get(url).await; assert_eq!(code, 200, "{}", response); - let expected = DEFAULT_SETTINGS_VALUES.get(stringify!($setting)).unwrap(); - assert_eq!(expected, &response); + let expected = crate::json!($default_value); + assert_eq!(expected, response); } } )* @@ -438,26 +381,106 @@ macro_rules! test_setting_routes { } test_setting_routes!( - filterable_attributes put, - displayed_attributes put, - localized_attributes put, - searchable_attributes put, - distinct_attribute put, - stop_words put, - separator_tokens put, - non_separator_tokens put, - dictionary put, - ranking_rules put, - synonyms put, - pagination patch, - faceting patch, - search_cutoff_ms put, - embedders patch, - facet_search put, - prefix_search put, - proximity_precision put, - sortable_attributes put, - typo_tolerance patch, + { + setting: filterable_attributes, + update_verb: put, + default_value: [] + }, + { + setting: displayed_attributes, + update_verb: put, + default_value: ["*"] + }, + { + setting: localized_attributes, + update_verb: put, + default_value: null + }, + { + setting: searchable_attributes, + update_verb: put, + default_value: ["*"] + }, + { + setting: distinct_attribute, + update_verb: put, + default_value: null + }, + { + setting: stop_words, + update_verb: put, + default_value: [] + }, + { + setting: separator_tokens, + update_verb: put, + default_value: [] + }, + { + setting: non_separator_tokens, + update_verb: put, + default_value: [] + }, + { + setting: dictionary, + update_verb: put, + default_value: [] + }, + { + setting: ranking_rules, + update_verb: put, + default_value: ["words", "typo", "proximity", "attribute", "sort", "exactness"] + }, + { + setting: synonyms, + update_verb: put, + default_value: {} + }, + { + setting: pagination, + update_verb: patch, + default_value: {"maxTotalHits": 1000} + }, + { + setting: faceting, + update_verb: patch, + default_value: {"maxValuesPerFacet": 100, "sortFacetValuesBy": {"*": "alpha"}} + }, + { + setting: search_cutoff_ms, + update_verb: put, + default_value: null + }, + { + setting: embedders, + update_verb: patch, + default_value: null + }, + { + setting: facet_search, + update_verb: put, + default_value: true + }, + { + setting: prefix_search, + update_verb: put, + default_value: "indexingTime" + }, + { + setting: proximity_precision, + update_verb: put, + default_value: "byWord" + }, + { + setting: sortable_attributes, + update_verb: put, + default_value: [] + }, + { + setting: typo_tolerance, + update_verb: patch, + default_value: {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}, "disableOnWords": [], "disableOnAttributes": []} + }, ); #[actix_rt::test] From 90b428a8c3d5930133870cb14d5e950baed1a1ad Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 28 Nov 2024 15:16:13 +0100 Subject: [PATCH 4/4] Apply change requests --- .../src/routes/indexes/settings.rs | 6 + .../tests/settings/get_settings.rs | 360 +++++++++--------- 2 files changed, 186 insertions(+), 180 deletions(-) diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index bb24fc880..b2922e5ff 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -17,6 +17,12 @@ use crate::extractors::authentication::GuardedData; use crate::routes::{get_task_id, is_dry_run, SummarizedTaskView}; use crate::Opt; +/// This macro generates the routes for the settings. +/// +/// It takes a list of settings and generates a module for each setting. +/// Each module contains the `get`, `update` and `delete` routes for the setting. +/// +/// It also generates a `configure` function that configures the routes for the settings. macro_rules! make_setting_routes { ($({route: $route:literal, update_verb: $update_verb:ident, value_type: $type:ty, err_type: $err_ty:ty, attr: $attr:ident, camelcase_attr: $camelcase_attr:literal, analytics: $analytics:ident},)*) => { $( diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index b9e10033a..55d9441ee 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -1,6 +1,186 @@ use crate::common::Server; use crate::json; +macro_rules! test_setting_routes { + ($({setting: $setting:ident, update_verb: $update_verb:ident, default_value: $default_value:tt},) *) => { + $( + mod $setting { + use crate::common::Server; + + #[actix_rt::test] + async fn get_unexisting_index() { + let server = Server::new().await; + let url = format!("/indexes/test/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (_response, code) = server.service.get(url).await; + assert_eq!(code, 404); + } + + #[actix_rt::test] + async fn update_unexisting_index() { + let server = Server::new().await; + let url = format!("/indexes/test/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (response, code) = server.service.$update_verb(url, serde_json::Value::Null.into()).await; + assert_eq!(code, 202, "{}", response); + server.index("").wait_task(0).await; + let (response, code) = server.index("test").get().await; + assert_eq!(code, 200, "{}", response); + } + + #[actix_rt::test] + async fn delete_unexisting_index() { + let server = Server::new().await; + let url = format!("/indexes/test/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (_, code) = server.service.delete(url).await; + assert_eq!(code, 202); + let response = server.index("").wait_task(0).await; + assert_eq!(response["status"], "failed"); + } + + #[actix_rt::test] + async fn get_default() { + let server = Server::new().await; + let index = server.index("test"); + let (response, code) = index.create(None).await; + assert_eq!(code, 202, "{}", response); + index.wait_task(0).await; + let url = format!("/indexes/test/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (response, code) = server.service.get(url).await; + assert_eq!(code, 200, "{}", response); + let expected = crate::json!($default_value); + assert_eq!(expected, response); + } + } + )* + + #[actix_rt::test] + async fn all_setting_tested() { + let expected = std::collections::BTreeSet::from_iter(meilisearch::routes::indexes::settings::ALL_SETTINGS_NAMES.iter()); + let tested = std::collections::BTreeSet::from_iter([$(stringify!($setting)),*].iter()); + let diff: Vec<_> = expected.difference(&tested).collect(); + assert!(diff.is_empty(), "Not all settings were tested, please add the following settings to the `test_setting_routes!` macro: {:?}", diff); + } + }; +} + +test_setting_routes!( + { + setting: filterable_attributes, + update_verb: put, + default_value: [] + }, + { + setting: displayed_attributes, + update_verb: put, + default_value: ["*"] + }, + { + setting: localized_attributes, + update_verb: put, + default_value: null + }, + { + setting: searchable_attributes, + update_verb: put, + default_value: ["*"] + }, + { + setting: distinct_attribute, + update_verb: put, + default_value: null + }, + { + setting: stop_words, + update_verb: put, + default_value: [] + }, + { + setting: separator_tokens, + update_verb: put, + default_value: [] + }, + { + setting: non_separator_tokens, + update_verb: put, + default_value: [] + }, + { + setting: dictionary, + update_verb: put, + default_value: [] + }, + { + setting: ranking_rules, + update_verb: put, + default_value: ["words", "typo", "proximity", "attribute", "sort", "exactness"] + }, + { + setting: synonyms, + update_verb: put, + default_value: {} + }, + { + setting: pagination, + update_verb: patch, + default_value: {"maxTotalHits": 1000} + }, + { + setting: faceting, + update_verb: patch, + default_value: {"maxValuesPerFacet": 100, "sortFacetValuesBy": {"*": "alpha"}} + }, + { + setting: search_cutoff_ms, + update_verb: put, + default_value: null + }, + { + setting: embedders, + update_verb: patch, + default_value: null + }, + { + setting: facet_search, + update_verb: put, + default_value: true + }, + { + setting: prefix_search, + update_verb: put, + default_value: "indexingTime" + }, + { + setting: proximity_precision, + update_verb: put, + default_value: "byWord" + }, + { + setting: sortable_attributes, + update_verb: put, + default_value: [] + }, + { + setting: typo_tolerance, + update_verb: patch, + default_value: {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}, "disableOnWords": [], "disableOnAttributes": []} + }, +); + #[actix_rt::test] async fn get_settings_unexisting_index() { let server = Server::new().await; @@ -303,186 +483,6 @@ async fn error_update_setting_unexisting_index_invalid_uid() { "###); } -macro_rules! test_setting_routes { - ($({setting: $setting:ident, update_verb: $update_verb:ident, default_value: $default_value:tt},) *) => { - $( - mod $setting { - use crate::common::Server; - - #[actix_rt::test] - async fn get_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (_response, code) = server.service.get(url).await; - assert_eq!(code, 404); - } - - #[actix_rt::test] - async fn update_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (response, code) = server.service.$update_verb(url, serde_json::Value::Null.into()).await; - assert_eq!(code, 202, "{}", response); - server.index("").wait_task(0).await; - let (response, code) = server.index("test").get().await; - assert_eq!(code, 200, "{}", response); - } - - #[actix_rt::test] - async fn delete_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (_, code) = server.service.delete(url).await; - assert_eq!(code, 202); - let response = server.index("").wait_task(0).await; - assert_eq!(response["status"], "failed"); - } - - #[actix_rt::test] - async fn get_default() { - let server = Server::new().await; - let index = server.index("test"); - let (response, code) = index.create(None).await; - assert_eq!(code, 202, "{}", response); - index.wait_task(0).await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (response, code) = server.service.get(url).await; - assert_eq!(code, 200, "{}", response); - let expected = crate::json!($default_value); - assert_eq!(expected, response); - } - } - )* - - #[actix_rt::test] - async fn all_setting_tested() { - let expected = std::collections::BTreeSet::from_iter(meilisearch::routes::indexes::settings::ALL_SETTINGS_NAMES.iter()); - let tested = std::collections::BTreeSet::from_iter([$(stringify!($setting)),*].iter()); - let diff: Vec<_> = expected.difference(&tested).collect(); - assert!(diff.is_empty(), "Not all settings were tested, please add the following settings to the `test_setting_routes!` macro: {:?}", diff); - } - }; -} - -test_setting_routes!( - { - setting: filterable_attributes, - update_verb: put, - default_value: [] - }, - { - setting: displayed_attributes, - update_verb: put, - default_value: ["*"] - }, - { - setting: localized_attributes, - update_verb: put, - default_value: null - }, - { - setting: searchable_attributes, - update_verb: put, - default_value: ["*"] - }, - { - setting: distinct_attribute, - update_verb: put, - default_value: null - }, - { - setting: stop_words, - update_verb: put, - default_value: [] - }, - { - setting: separator_tokens, - update_verb: put, - default_value: [] - }, - { - setting: non_separator_tokens, - update_verb: put, - default_value: [] - }, - { - setting: dictionary, - update_verb: put, - default_value: [] - }, - { - setting: ranking_rules, - update_verb: put, - default_value: ["words", "typo", "proximity", "attribute", "sort", "exactness"] - }, - { - setting: synonyms, - update_verb: put, - default_value: {} - }, - { - setting: pagination, - update_verb: patch, - default_value: {"maxTotalHits": 1000} - }, - { - setting: faceting, - update_verb: patch, - default_value: {"maxValuesPerFacet": 100, "sortFacetValuesBy": {"*": "alpha"}} - }, - { - setting: search_cutoff_ms, - update_verb: put, - default_value: null - }, - { - setting: embedders, - update_verb: patch, - default_value: null - }, - { - setting: facet_search, - update_verb: put, - default_value: true - }, - { - setting: prefix_search, - update_verb: put, - default_value: "indexingTime" - }, - { - setting: proximity_precision, - update_verb: put, - default_value: "byWord" - }, - { - setting: sortable_attributes, - update_verb: put, - default_value: [] - }, - { - setting: typo_tolerance, - update_verb: patch, - default_value: {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}, "disableOnWords": [], "disableOnAttributes": []} - }, -); - #[actix_rt::test] async fn error_set_invalid_ranking_rules() { let server = Server::new().await;