diff --git a/Cargo.lock b/Cargo.lock index 196deb1bb..3dfc74f7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1923,7 +1923,7 @@ dependencies = [ [[package]] name = "pest" version = "2.1.3" -source = "git+https://github.com/MarinPostma/pest.git?tag=meilisearch-patch1#e1031ad0134d5e9893c470dbea50811b2b746926" +source = "git+https://github.com/pest-parser/pest.git?rev=51fd1d49f1041f7839975664ef71fe15c7dcaf67#51fd1d49f1041f7839975664ef71fe15c7dcaf67" dependencies = [ "ucd-trie", ] diff --git a/meilisearch-http/src/routes/document.rs b/meilisearch-http/src/routes/document.rs index f565c1e6b..e8fa0f646 100644 --- a/meilisearch-http/src/routes/document.rs +++ b/meilisearch-http/src/routes/document.rs @@ -3,14 +3,14 @@ use std::collections::{BTreeSet, HashSet}; use actix_web::{delete, get, post, put}; use actix_web::{web, HttpResponse}; use indexmap::IndexMap; -use meilisearch_core::{update, Index}; +use meilisearch_core::{update, MainReader}; use serde_json::Value; use serde::Deserialize; +use crate::Data; use crate::error::{Error, ResponseError}; use crate::helpers::Authentication; use crate::routes::{IndexParam, IndexUpdateResponse}; -use crate::Data; type Document = IndexMap; diff --git a/meilisearch-http/tests/common.rs b/meilisearch-http/tests/common.rs index da2bc39ad..0cdd3b618 100644 --- a/meilisearch-http/tests/common.rs +++ b/meilisearch-http/tests/common.rs @@ -15,15 +15,24 @@ use meilisearch_http::option::Opt; #[macro_export] macro_rules! test_post_get_search { ($server:expr, $query:expr, |$response:ident, $status_code:ident | $block:expr) => { - let post_query: meilisearch_http::routes::search::SearchQueryPost = serde_json::from_str(&$query.clone().to_string()).unwrap(); + let post_query: meilisearch_http::routes::search::SearchQueryPost = + serde_json::from_str(&$query.clone().to_string()).unwrap(); let get_query: meilisearch_http::routes::search::SearchQuery = post_query.into(); let get_query = ::serde_url_params::to_string(&get_query).unwrap(); let ($response, $status_code) = $server.search_get(&get_query).await; - let _ =::std::panic::catch_unwind(|| $block) - .map_err(|e| panic!("panic in get route: {:?}", e.downcast_ref::<&str>().unwrap())); + let _ = ::std::panic::catch_unwind(|| $block).map_err(|e| { + panic!( + "panic in get route: {:?}", + e.downcast_ref::<&str>().unwrap() + ) + }); let ($response, $status_code) = $server.search_post($query).await; - let _ = ::std::panic::catch_unwind(|| $block) - .map_err(|e| panic!("panic in post route: {:?}", e.downcast_ref::<&str>().unwrap())); + let _ = ::std::panic::catch_unwind(|| $block).map_err(|e| { + panic!( + "panic in post route: {:?}", + e.downcast_ref::<&str>().unwrap() + ) + }); }; } @@ -61,7 +70,6 @@ impl Server { } pub async fn test_server() -> Self { - let mut server = Self::with_uid("test"); let body = json!({ @@ -151,7 +159,8 @@ impl Server { pub async fn get_request(&mut self, url: &str) -> (Value, StatusCode) { eprintln!("get_request: {}", url); - let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; + let mut app = + test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; let req = test::TestRequest::get().uri(url).to_request(); let res = test::call_service(&mut app, req).await; @@ -165,7 +174,8 @@ impl Server { pub async fn post_request(&self, url: &str, body: Value) -> (Value, StatusCode) { eprintln!("post_request: {}", url); - let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; + let mut app = + test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; let req = test::TestRequest::post() .uri(url) @@ -183,8 +193,7 @@ impl Server { eprintln!("post_request_async: {}", url); let (response, status_code) = self.post_request(url, body).await; - // eprintln!("response: {}", response); - assert_eq!(status_code, 202); + eprintln!("response: {}", response); assert!(response["updateId"].as_u64().is_some()); self.wait_update_id(response["updateId"].as_u64().unwrap()) .await; @@ -194,7 +203,8 @@ impl Server { pub async fn put_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) { eprintln!("put_request: {}", url); - let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; + let mut app = + test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; let req = test::TestRequest::put() .uri(url) @@ -222,7 +232,8 @@ impl Server { pub async fn delete_request(&mut self, url: &str) -> (Value, StatusCode) { eprintln!("delete_request: {}", url); - let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; + let mut app = + test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await; let req = test::TestRequest::delete().uri(url).to_request(); let res = test::call_service(&mut app, req).await; @@ -340,9 +351,9 @@ impl Server { self.delete_request_async(&url).await } - pub async fn delete_multiple_documents(&mut self, body: Value) { + pub async fn delete_multiple_documents(&mut self, body: Value) -> (Value, StatusCode) { let url = format!("/indexes/{}/documents/delete-batch", self.uid); - self.post_request_async(&url, body).await; + self.post_request_async(&url, body).await } pub async fn get_all_settings(&mut self) -> (Value, StatusCode) { @@ -355,6 +366,11 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_all_settings_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_all_settings(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings", self.uid); self.delete_request_async(&url).await @@ -390,6 +406,11 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_distinct_attribute_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_distinct_attribute(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); self.delete_request_async(&url).await @@ -410,6 +431,11 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_searchable_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_searchable_attributes(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); self.delete_request_async(&url).await @@ -425,11 +451,39 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_displayed_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_displayed_attributes(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); self.delete_request_async(&url).await } + pub async fn get_attributes_for_faceting(&mut self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + self.get_request(&url).await + } + + pub async fn update_attributes_for_faceting(&mut self, body: Value) { + let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + self.post_request_async(&url, body).await; + } + + pub async fn update_attributes_for_faceting_sync( + &mut self, + body: Value, + ) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + self.post_request(&url, body).await + } + + pub async fn delete_attributes_for_faceting(&mut self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + self.delete_request_async(&url).await + } + pub async fn get_synonyms(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/synonyms", self.uid); self.get_request(&url).await @@ -440,6 +494,11 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_synonyms_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/synonyms", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_synonyms(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/synonyms", self.uid); self.delete_request_async(&url).await @@ -455,6 +514,11 @@ impl Server { self.post_request_async(&url, body).await; } + pub async fn update_stop_words_sync(&mut self, body: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings/stop-words", self.uid); + self.post_request(&url, body).await + } + pub async fn delete_stop_words(&mut self) -> (Value, StatusCode) { let url = format!("/indexes/{}/settings/stop-words", self.uid); self.delete_request_async(&url).await diff --git a/meilisearch-http/tests/documents_add.rs b/meilisearch-http/tests/documents_add.rs index 140a194c3..382a1ed43 100644 --- a/meilisearch-http/tests/documents_add.rs +++ b/meilisearch-http/tests/documents_add.rs @@ -220,70 +220,3 @@ async fn documents_with_same_id_are_overwritten() { "test2" ); } - -#[actix_rt::test] -async fn create_index_lazy_by_pushing_documents() { - let mut server = common::Server::with_uid("movies"); - - // 1 - Add documents - - let body = json!([{ - "title": "Test", - "comment": "comment test" - }]); - - let url = "/indexes/movies/documents?primaryKey=title"; - let (response, status_code) = server.post_request(&url, body).await; - eprintln!("{:#?}", response); - assert_eq!(status_code, 202); - let update_id = response["updateId"].as_u64().unwrap(); - server.wait_update_id(update_id).await; - - // 3 - Check update success - - let (response, status_code) = server.get_update_status(update_id).await; - assert_eq!(status_code, 200); - assert_eq!(response["status"], "processed"); -} - -#[actix_rt::test] -async fn create_index_lazy_by_pushing_documents_and_discover_pk() { - let mut server = common::Server::with_uid("movies"); - - // 1 - Add documents - - let body = json!([{ - "id": 1, - "title": "Test", - "comment": "comment test" - }]); - - let url = "/indexes/movies/documents"; - let (response, status_code) = server.post_request(&url, body).await; - eprintln!("{:#?}", response); - assert_eq!(status_code, 202); - let update_id = response["updateId"].as_u64().unwrap(); - server.wait_update_id(update_id).await; - - // 3 - Check update success - - let (response, status_code) = server.get_update_status(update_id).await; - assert_eq!(status_code, 200); - assert_eq!(response["status"], "processed"); -} - -#[actix_rt::test] -async fn create_index_lazy_by_pushing_documents_with_wwrong_name() { - let mut server = common::Server::with_uid("wrong&name"); - - let body = json!([{ - "title": "Test", - "comment": "comment test" - }]); - - let url = "/indexes/wrong&name/documents?primaryKey=title"; - let (response, status_code) = server.post_request(&url, body).await; - eprintln!("{:#?}", response); - assert_eq!(status_code, 400); - assert_eq!(response["errorCode"], "invalid_index_uid"); -} diff --git a/meilisearch-http/tests/lazy_index_creation.rs b/meilisearch-http/tests/lazy_index_creation.rs new file mode 100644 index 000000000..6730db82e --- /dev/null +++ b/meilisearch-http/tests/lazy_index_creation.rs @@ -0,0 +1,446 @@ +use serde_json::json; + +mod common; + +#[actix_rt::test] +async fn create_index_lazy_by_pushing_documents() { + let mut server = common::Server::with_uid("movies"); + + // 1 - Add documents + + let body = json!([{ + "title": "Test", + "comment": "comment test" + }]); + + let url = "/indexes/movies/documents?primaryKey=title"; + let (response, status_code) = server.post_request(&url, body).await; + assert_eq!(status_code, 202); + let update_id = response["updateId"].as_u64().unwrap(); + server.wait_update_id(update_id).await; + + // 3 - Check update success + + let (response, status_code) = server.get_update_status(update_id).await; + assert_eq!(status_code, 200); + assert_eq!(response["status"], "processed"); +} + +#[actix_rt::test] +async fn create_index_lazy_by_pushing_documents_and_discover_pk() { + let mut server = common::Server::with_uid("movies"); + + // 1 - Add documents + + let body = json!([{ + "id": 1, + "title": "Test", + "comment": "comment test" + }]); + + let url = "/indexes/movies/documents"; + let (response, status_code) = server.post_request(&url, body).await; + assert_eq!(status_code, 202); + let update_id = response["updateId"].as_u64().unwrap(); + server.wait_update_id(update_id).await; + + // 3 - Check update success + + let (response, status_code) = server.get_update_status(update_id).await; + assert_eq!(status_code, 200); + assert_eq!(response["status"], "processed"); +} + +#[actix_rt::test] +async fn create_index_lazy_by_pushing_documents_with_wrong_name() { + let server = common::Server::with_uid("wrong&name"); + + let body = json!([{ + "title": "Test", + "comment": "comment test" + }]); + + let url = "/indexes/wrong&name/documents?primaryKey=title"; + let (response, status_code) = server.post_request(&url, body).await; + assert_eq!(status_code, 400); + assert_eq!(response["errorCode"], "invalid_index_uid"); +} + +#[actix_rt::test] +async fn create_index_lazy_add_documents_failed() { + let mut server = common::Server::with_uid("wrong&name"); + + let body = json!([{ + "title": "Test", + "comment": "comment test" + }]); + + let url = "/indexes/wrong&name/documents"; + let (response, status_code) = server.post_request(&url, body).await; + assert_eq!(status_code, 400); + assert_eq!(response["errorCode"], "invalid_index_uid"); + + let (_, status_code) = server.get_index().await; + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_settings() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!({ + "rankingRules": [ + "typo", + "words", + "proximity", + "attribute", + "wordsPosition", + "exactness", + "desc(registered)", + "desc(age)", + ], + "distinctAttribute": "id", + "searchableAttributes": [ + "id", + "name", + "color", + "gender", + "email", + "phone", + "address", + "registered", + "about" + ], + "displayedAttributes": [ + "name", + "gender", + "email", + "registered", + "age", + ], + "stopWords": [ + "ad", + "in", + "ut", + ], + "synonyms": { + "road": ["street", "avenue"], + "street": ["avenue"], + }, + "attributesForFaceting": ["name"], + }); + + server.update_all_settings(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_settings_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!({ + "rankingRules": [ + "other", + "words", + "proximity", + "attribute", + "wordsPosition", + "exactness", + "desc(registered)", + "desc(age)", + ], + "distinctAttribute": "id", + "searchableAttributes": [ + "id", + "name", + "color", + "gender", + "email", + "phone", + "address", + "registered", + "about" + ], + "displayedAttributes": [ + "name", + "gender", + "email", + "registered", + "age", + ], + "stopWords": [ + "ad", + "in", + "ut", + ], + "synonyms": { + "road": ["street", "avenue"], + "street": ["avenue"], + }, + "anotherSettings": ["name"], + }); + + let (_, status_code) = server.update_all_settings_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_ranking_rules() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!([ + "typo", + "words", + "proximity", + "attribute", + "wordsPosition", + "exactness", + "desc(registered)", + "desc(age)", + ]); + + server.update_ranking_rules(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_ranking_rules_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!({ + "rankingRules": 123, + }); + + let (_, status_code) = server.update_ranking_rules_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_distinct_attribute() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!("type"); + + server.update_distinct_attribute(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_distinct_attribute_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (resp, status_code) = server.update_distinct_attribute_sync(body.clone()).await; + eprintln!("resp: {:?}", resp); + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (resp, status_code) = server.get_all_settings().await; + eprintln!("resp: {:?}", resp); + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_searchable_attributes() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(["title", "description"]); + + server.update_searchable_attributes(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_searchable_attributes_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (_, status_code) = server.update_searchable_attributes_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_displayed_attributes() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(["title", "description"]); + + server.update_displayed_attributes(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_displayed_attributes_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (_, status_code) = server.update_displayed_attributes_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_attributes_for_faceting() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(["title", "description"]); + + server.update_attributes_for_faceting(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_attributes_for_faceting_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (_, status_code) = server + .update_attributes_for_faceting_sync(body.clone()) + .await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_synonyms() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!({ + "road": ["street", "avenue"], + "street": ["avenue"], + }); + + server.update_synonyms(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_synonyms_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (_, status_code) = server.update_synonyms_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_stop_words() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(["le", "la", "les"]); + + server.update_stop_words(body.clone()).await; + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 200); +} + +#[actix_rt::test] +async fn create_index_lazy_by_sending_stop_words_with_error() { + let mut server = common::Server::with_uid("movies"); + // 2 - Send the settings + + let body = json!(123); + + let (_, status_code) = server.update_stop_words_sync(body.clone()).await; + assert_eq!(status_code, 400); + + // 3 - Get all settings and compare to the previous one + + let (_, status_code) = server.get_all_settings().await; + + assert_eq!(status_code, 404); +}