From 5c543f9d9442ee6de90aec7961b2a907f2a04842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 18 Aug 2022 11:33:22 +0200 Subject: [PATCH 1/3] Add a test for single document upload --- .../tests/documents/add_documents.rs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/meilisearch-http/tests/documents/add_documents.rs b/meilisearch-http/tests/documents/add_documents.rs index ebd5f58d3..c7e67d46f 100644 --- a/meilisearch-http/tests/documents/add_documents.rs +++ b/meilisearch-http/tests/documents/add_documents.rs @@ -52,6 +52,51 @@ async fn add_documents_test_json_content_types() { assert_eq!(response["taskUid"], 1); } +/// Here we try to send a single document instead of an array with a single document inside. +#[actix_rt::test] +async fn add_single_document_test_json_content_types() { + let document = json!({ + "id": 1, + "content": "Bouvier Bernois", + }); + + // this is a what is expected and should work + let server = Server::new().await; + let app = test::init_service(create_app!( + &server.service.meilisearch, + &server.service.auth, + true, + &server.service.options, + analytics::MockAnalytics::new(&server.service.options).0 + )) + .await; + // post + let req = test::TestRequest::post() + .uri("/indexes/dog/documents") + .set_payload(document.to_string()) + .insert_header(("content-type", "application/json")) + .to_request(); + let res = test::call_service(&app, req).await; + let status_code = res.status(); + let body = test::read_body(res).await; + let response: Value = serde_json::from_slice(&body).unwrap_or_default(); + assert_eq!(status_code, 202); + assert_eq!(response["taskUid"], 0); + + // put + let req = test::TestRequest::put() + .uri("/indexes/dog/documents") + .set_payload(document.to_string()) + .insert_header(("content-type", "application/json")) + .to_request(); + let res = test::call_service(&app, req).await; + let status_code = res.status(); + let body = test::read_body(res).await; + let response: Value = serde_json::from_slice(&body).unwrap_or_default(); + assert_eq!(status_code, 202); + assert_eq!(response["taskUid"], 1); +} + /// any other content-type is must be refused #[actix_rt::test] async fn error_add_documents_test_bad_content_types() { From 9b2036ac055ee80f6db775db3869046ff36ffcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 18 Aug 2022 11:55:14 +0200 Subject: [PATCH 2/3] Accept either an array of documents or a single document --- Cargo.lock | 3 +++ meilisearch-lib/Cargo.toml | 2 +- meilisearch-lib/src/document_formats.rs | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 627c9c0b2..2eddd276e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -983,6 +983,9 @@ name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +dependencies = [ + "serde", +] [[package]] name = "embedded-hal" diff --git a/meilisearch-lib/Cargo.toml b/meilisearch-lib/Cargo.toml index d3790a91c..d0ca59289 100644 --- a/meilisearch-lib/Cargo.toml +++ b/meilisearch-lib/Cargo.toml @@ -15,7 +15,7 @@ clap = { version = "3.1.6", features = ["derive", "env"] } crossbeam-channel = "0.5.2" csv = "1.1.6" derivative = "2.2.0" -either = "1.6.1" +either = { version = "1.6.1", features = ["serde"] } flate2 = "1.0.22" fs_extra = "1.2.0" fst = "0.4.7" diff --git a/meilisearch-lib/src/document_formats.rs b/meilisearch-lib/src/document_formats.rs index 72e899845..ebc98f3fb 100644 --- a/meilisearch-lib/src/document_formats.rs +++ b/meilisearch-lib/src/document_formats.rs @@ -2,9 +2,12 @@ use std::borrow::Borrow; use std::fmt::{self, Debug, Display}; use std::io::{self, BufReader, Read, Seek, Write}; +use either::Either; use meilisearch_types::error::{Code, ErrorCode}; use meilisearch_types::internal_error; use milli::documents::{DocumentsBatchBuilder, Error}; +use milli::Object; +use serde::Deserialize; type Result = std::result::Result; @@ -124,11 +127,18 @@ pub fn read_json(input: impl Read, writer: impl Write + Seek) -> Result { let mut builder = DocumentsBatchBuilder::new(writer); let reader = BufReader::new(input); - let objects: Vec<_> = serde_json::from_reader(reader) + #[derive(Deserialize, Debug)] + #[serde(transparent)] + struct ArrayOrSingleObject { + #[serde(with = "either::serde_untagged")] + inner: Either, Object>, + } + + let content: ArrayOrSingleObject = serde_json::from_reader(reader) .map_err(Error::Json) .map_err(|e| (PayloadType::Json, e))?; - for object in objects { + for object in content.inner.map_right(|o| vec![o]).into_inner() { builder .append_json_object(&object) .map_err(Into::into) From e32d5ef2b3fb1648d2020b414d33533846b90aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 18 Aug 2022 14:37:44 +0200 Subject: [PATCH 3/3] Fix the test with an uncomprehensible user error message --- meilisearch-http/tests/documents/add_documents.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meilisearch-http/tests/documents/add_documents.rs b/meilisearch-http/tests/documents/add_documents.rs index c7e67d46f..afee5b18c 100644 --- a/meilisearch-http/tests/documents/add_documents.rs +++ b/meilisearch-http/tests/documents/add_documents.rs @@ -372,7 +372,7 @@ async fn error_add_malformed_json_documents() { assert_eq!( response["message"], json!( - r#"The `json` payload provided is malformed. `Couldn't serialize document value: invalid type: string "0123456789012345678901234567...890123456789012345678901234567890123456789", expected a sequence at line 1 column 102`."# + r#"The `json` payload provided is malformed. `Couldn't serialize document value: data did not match any variant of untagged enum Either`."# ) ); assert_eq!(response["code"], json!("malformed_payload")); @@ -395,7 +395,7 @@ async fn error_add_malformed_json_documents() { assert_eq!(status_code, 400); assert_eq!( response["message"], - json!("The `json` payload provided is malformed. `Couldn't serialize document value: invalid type: string \"0123456789012345678901234567...90123456789012345678901234567890123456789m\", expected a sequence at line 1 column 103`.") + json!("The `json` payload provided is malformed. `Couldn't serialize document value: data did not match any variant of untagged enum Either`.") ); assert_eq!(response["code"], json!("malformed_payload")); assert_eq!(response["type"], json!("invalid_request"));