MeiliSearch/meilisearch/tests/search/locales.rs
2024-09-23 17:13:27 +02:00

1579 lines
56 KiB
Rust

use meili_snap::*;
use once_cell::sync::Lazy;
use crate::common::{Server, Value};
use crate::json;
static NESTED_DOCUMENTS: Lazy<Value> = Lazy::new(|| {
json!([
{
"id": 852,
"document_en": {
"name": "Attack on Titan",
"description": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author": "Hajime Isayama",
},
"document_ja": {
"name": "進撃の巨人",
"description": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author": "諫山 創",
},
"document_zh": {
"name": "进击的巨人",
"description": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"author": "諫山創",
},
"_vectors": { "manual": [1, 2, 3]},
},
{
"id": 654,
"document_en":
{
"name": "One Piece",
"description": "One Piece is a Japanese manga series written and illustrated by Eiichiro Oda",
"author": "Eiichiro Oda",
},
"document_ja": {
"name": "ワンピース",
"description": "ワンピースは、日本の漫画シリーズであり、尾田 栄一郎によって作画されている。",
"author": "尾田 栄一郎",
},
"document_zh": {
"name": "ONE PIECE",
"description": "海贼王》是尾田荣一郎创作的日本漫画系列。",
"author": "尾田 栄一郎",
},
"_vectors": { "manual": [1, 2, 54] },
}
])
});
static DOCUMENTS: Lazy<Value> = Lazy::new(|| {
json!([
{
"id": 852,
"name_en": "Attack on Titan",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author_en": "Hajime Isayama",
"name_ja": "進撃の巨人",
"description_ja": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author_ja": "諫山 創",
"_vectors": { "manual": [1, 2, 3]},
},
{
"id": 853,
"name_zh": "进击的巨人",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"author_zh": "諫山創",
"_vectors": { "manual": [1, 2, 3]},
},
{
"id": 654,
"name_en": "One Piece",
"description_en": "One Piece is a Japanese manga series written and illustrated by Eiichiro Oda",
"author_en": "Eiichiro Oda",
"name_ja": "ワンピース",
"description_ja": "ワンピースは、日本の漫画シリーズであり、尾田 栄一郎によって作画されている。",
"author_ja": "尾田 栄一郎",
"_vectors": { "manual": [1, 2, 54] },
},
{
"id": 655,
"name_zh": "ONE PIECE",
"description_zh": "海贼王》是尾田荣一郎创作的日本漫画系列。",
"author_zh": "尾田 栄一郎",
"_vectors": { "manual": [1, 2, 54] },
}
])
});
#[actix_rt::test]
async fn simple_search() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
index
.update_settings(
json!({"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"]}),
)
.await;
index.add_documents(documents, None).await;
index.wait_task(1).await;
// english
index
.search(json!({"q": "Atta", "attributesToHighlight": ["*"]}), |response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_en": "Attack on Titan",
"name_ja": "進撃の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": 852,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_en": "<em>Atta</em>ck on Titan",
"name_ja": "進撃の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "<em>Atta</em>ck on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": "852",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "Atta",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
})
.await;
// japanese
index
.search(json!({"q": "進撃", "attributesToHighlight": ["*"]}), |response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进击</em>的巨人",
"author_zh": "諫山創",
"description_zh": "<em>进击</em>的巨人是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "進撃",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
})
.await;
index
.search(
json!({"q": "進撃", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_en": "Attack on Titan",
"name_ja": "進撃の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": 852,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_en": "Attack on Titan",
"name_ja": "<em>進撃</em>の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "<em>進撃</em>の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": "852",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
},
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "進撃",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 2
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// chinese
index
.search(json!({"q": "进击", "attributesToHighlight": ["*"]}), |response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进击</em>的巨人",
"author_zh": "諫山創",
"description_zh": "<em>进击</em>的巨人是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
},
{
"name_en": "Attack on Titan",
"name_ja": "進撃の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": 852,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_en": "Attack on Titan",
"name_ja": "<em>進撃</em>の巨人",
"author_en": "Hajime Isayama",
"author_ja": "諫山 創",
"description_en": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"description_ja": "<em>進撃</em>の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"id": "852",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "进击",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 2
}
"###);
snapshot!(code, @"200 OK");
})
.await;
}
#[actix_rt::test]
async fn force_locales() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(
json!({
"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["name_ja", "name_zh", "author_ja", "author_zh", "description_ja", "description_zh"], "locales": ["jpn"]}
]
}),
)
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// chinese detection
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn force_locales_with_pattern() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(
json!({
"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_ja", "*_zh"], "locales": ["jpn"]}
]
}),
)
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// chinese detection
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn force_locales_with_pattern_nested() {
let server = Server::new().await;
let index = server.index("test");
let documents = NESTED_DOCUMENTS.clone();
let (response, _) = index
.update_settings(json!({
"searchableAttributes": ["document_en", "document_ja", "document_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["document_ja.*", "*_zh.*"], "locales": ["jpn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// chinese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["cmn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"document_en": {
"name": "Attack on Titan",
"description": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author": "Hajime Isayama"
},
"document_ja": {
"name": "進撃の巨人",
"description": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author": "諫山 創"
},
"document_zh": {
"name": "进击的巨人",
"description": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"author": "諫山創"
},
"id": 852,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"document_en": {
"name": "Attack on Titan",
"description": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author": "Hajime Isayama"
},
"document_ja": {
"name": "進撃の巨人",
"description": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author": "諫山 創"
},
"document_zh": {
"name": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"description": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"author": "諫山創"
},
"id": "852",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn force_different_locales_with_pattern() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(
json!({
"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_zh"], "locales": ["jpn"]},
// force chinese
{"attributePatterns": ["*_ja"], "locales": ["cmn"]}
]
}),
)
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// force chinese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["cmn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn auto_infer_locales_at_search_with_attributes_to_search_on() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(
json!({
"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_zh"], "locales": ["jpn"]},
// force chinese
{"attributePatterns": ["*_ja"], "locales": ["cmn"]},
// any language
{"attributePatterns": ["*_en"], "locales": []}
]
}),
)
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// auto infer any language
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// should infer chinese
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"], "attributesToSearchOn": ["name_zh", "description_zh"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn auto_infer_locales_at_search() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(
json!({
"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*"], "locales": ["jpn"]},
]
}),
)
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
index
.search(
json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"name_zh": "进击的巨人",
"author_zh": "諫山創",
"description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"id": 853,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"name_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"author_zh": "諫山創",
"description_zh": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"id": "853",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn force_different_locales_with_pattern_nested() {
let server = Server::new().await;
let index = server.index("test");
let documents = NESTED_DOCUMENTS.clone();
let (response, _) = index
.update_settings(json!({
"searchableAttributes": ["document_en", "document_ja", "document_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_zh.*"], "locales": ["jpn"]},
// force chinese
{"attributePatterns": ["document_ja.*", "document_zh.*"], "locales": ["cmn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
// chinese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["cmn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [
{
"document_en": {
"name": "Attack on Titan",
"description": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author": "Hajime Isayama"
},
"document_ja": {
"name": "進撃の巨人",
"description": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author": "諫山 創"
},
"document_zh": {
"name": "进击的巨人",
"description": "进击的巨人是日本的漫画系列,由諫山 創作画。",
"author": "諫山創"
},
"id": 852,
"_vectors": {
"manual": [
1.0,
2.0,
3.0
]
},
"_formatted": {
"document_en": {
"name": "Attack on Titan",
"description": "Attack on Titan is a Japanese manga series written and illustrated by Hajime Isayama",
"author": "Hajime Isayama"
},
"document_ja": {
"name": "進撃の巨人",
"description": "進撃の巨人は、日本の漫画シリーズであり、諫山 創によって作画されている。",
"author": "諫山 創"
},
"document_zh": {
"name": "<em>进</em><em>击</em><em>的</em><em>巨人</em>",
"description": "<em>进</em><em>击</em><em>的</em><em>巨人</em>是日本的漫画系列,由諫山 創作画。",
"author": "諫山創"
},
"id": "852",
"_vectors": {
"manual": [
"1.0",
"2.0",
"3.0"
]
}
}
}
],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn settings_change() {
let server = Server::new().await;
let index = server.index("test");
let documents = NESTED_DOCUMENTS.clone();
index.add_documents(documents, None).await;
index.wait_task(0).await;
let (response, _) = index
.update_settings(json!({
"searchableAttributes": ["document_en", "document_ja", "document_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["document_ja.*", "*_zh.*"], "locales": ["jpn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 1,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.wait_task(1).await;
// chinese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["cmn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// change settings
let (response, _) = index
.update_settings(json!({
"searchableAttributes": ["document_en", "document_ja", "document_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_zh.*"], "locales": ["jpn"]},
// force chinese
{"attributePatterns": ["document_ja.*"], "locales": ["cmn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 2,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.wait_task(2).await;
// chinese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["cmn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
// force japanese
index
.search(
json!({"q": "\"进击的巨人\"", "locales": ["jpn"], "attributesToHighlight": ["*"]}),
|response, code| {
snapshot!(response, @r###"
{
"hits": [],
"query": "\"进击的巨人\"",
"processingTimeMs": "[duration]",
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
"###);
snapshot!(code, @"200 OK");
},
)
.await;
}
#[actix_rt::test]
async fn invalid_locales() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
index
.update_settings(
json!({"searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"]}),
)
.await;
index.add_documents(documents, None).await;
index.wait_task(1).await;
let (response, code) = index.search_post(json!({"q": "Atta", "locales": ["invalid"]})).await;
snapshot!(code, @"400 Bad Request");
snapshot!(json_string!(response), @r###"
{
"message": "Unknown value `invalid` at `.locales[0]`: expected one of `epo`, `eng`, `rus`, `cmn`, `spa`, `por`, `ita`, `ben`, `fra`, `deu`, `ukr`, `kat`, `ara`, `hin`, `jpn`, `heb`, `yid`, `pol`, `amh`, `jav`, `kor`, `nob`, `dan`, `swe`, `fin`, `tur`, `nld`, `hun`, `ces`, `ell`, `bul`, `bel`, `mar`, `kan`, `ron`, `slv`, `hrv`, `srp`, `mkd`, `lit`, `lav`, `est`, `tam`, `vie`, `urd`, `tha`, `guj`, `uzb`, `pan`, `aze`, `ind`, `tel`, `pes`, `mal`, `ori`, `mya`, `nep`, `sin`, `khm`, `tuk`, `aka`, `zul`, `sna`, `afr`, `lat`, `slk`, `cat`, `tgl`, `hye`, `zho`",
"code": "invalid_search_locales",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_search_locales"
}
"###);
let (response, code) = index
.search_get(&yaup::to_string(&json!({"q": "Atta", "locales": ["invalid"]})).unwrap())
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(json_string!(response), @r###"
{
"message": "Invalid value in parameter `locales`: Unsupported locale `invalid`, expected one of `epo`, `eng`, `rus`, `cmn`, `spa`, `por`, `ita`, `ben`, `fra`, `deu`, `ukr`, `kat`, `ara`, `hin`, `jpn`, `heb`, `yid`, `pol`, `amh`, `jav`, `kor`, `nob`, `dan`, `swe`, `fin`, `tur`, `nld`, `hun`, `ces`, `ell`, `bul`, `bel`, `mar`, `kan`, `ron`, `slv`, `hrv`, `srp`, `mkd`, `lit`, `lav`, `est`, `tam`, `vie`, `urd`, `tha`, `guj`, `uzb`, `pan`, `aze`, `ind`, `tel`, `pes`, `mal`, `ori`, `mya`, `nep`, `sin`, `khm`, `tuk`, `aka`, `zul`, `sna`, `afr`, `lat`, `slk`, `cat`, `tgl`, `hye`, `zho`",
"code": "invalid_search_locales",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_search_locales"
}
"###);
}
#[actix_rt::test]
async fn invalid_localized_attributes_rules() {
let server = Server::new().await;
let index = server.index("test");
let (response, _) = index
.update_settings(json!({
"localizedAttributes": [
{"attributePatterns": ["*_ja", "*_zh"], "locales": ["japan"]}
]
}))
.await;
snapshot!(response, @r###"
{
"message": "Unknown value `japan` at `.localizedAttributes[0].locales[0]`: expected one of `epo`, `eng`, `rus`, `cmn`, `spa`, `por`, `ita`, `ben`, `fra`, `deu`, `ukr`, `kat`, `ara`, `hin`, `jpn`, `heb`, `yid`, `pol`, `amh`, `jav`, `kor`, `nob`, `dan`, `swe`, `fin`, `tur`, `nld`, `hun`, `ces`, `ell`, `bul`, `bel`, `mar`, `kan`, `ron`, `slv`, `hrv`, `srp`, `mkd`, `lit`, `lav`, `est`, `tam`, `vie`, `urd`, `tha`, `guj`, `uzb`, `pan`, `aze`, `ind`, `tel`, `pes`, `mal`, `ori`, `mya`, `nep`, `sin`, `khm`, `tuk`, `aka`, `zul`, `sna`, `afr`, `lat`, `slk`, `cat`, `tgl`, `hye`, `zho`",
"code": "invalid_settings_localized_attributes",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_settings_localized_attributes"
}
"###);
let (response, _) = index
.update_settings(json!({
"localizedAttributes": [
{"attributePatterns": ["*_ja", "*_zh"], "locales": "jpn"}
]
}))
.await;
snapshot!(response, @r###"
{
"message": "Invalid value type at `.localizedAttributes[0].locales`: expected an array, but found a string: `\"jpn\"`",
"code": "invalid_settings_localized_attributes",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_settings_localized_attributes"
}
"###);
let (response, _) = index
.update_settings(json!({
"localizedAttributes": [
{"attributePatterns": "*_ja", "locales": ["jpn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"message": "Invalid value type at `.localizedAttributes[0].attributePatterns`: expected an array, but found a string: `\"*_ja\"`",
"code": "invalid_settings_localized_attributes",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_settings_localized_attributes"
}
"###);
let (response, _) = index
.update_settings(json!({
"localizedAttributes": [
{"locales": ["jpn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"message": "Missing field `attributePatterns` inside `.localizedAttributes[0]`",
"code": "invalid_settings_localized_attributes",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_settings_localized_attributes"
}
"###);
}
#[actix_rt::test]
async fn simple_facet_search() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(json!({
"filterableAttributes": ["name_en", "name_ja", "name_zh"],
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
let (response, _) = index
.facet_search(json!({"facetName": "name_zh", "facetQuery": "進撃", "locales": ["cmn"]}))
.await;
snapshot!(response, @r###"
{
"facetHits": [
{
"value": "进击的巨人",
"count": 1
}
],
"facetQuery": "進撃",
"processingTimeMs": "[duration]"
}
"###);
let (response, _) = index
.facet_search(json!({"facetName": "name_zh", "facetQuery": "進撃", "locales": ["jpn"]}))
.await;
snapshot!(response, @r###"
{
"facetHits": [
{
"value": "进击的巨人",
"count": 1
}
],
"facetQuery": "進撃",
"processingTimeMs": "[duration]"
}
"###);
}
#[actix_rt::test]
async fn facet_search_with_localized_attributes() {
let server = Server::new().await;
let index = server.index("test");
let documents = DOCUMENTS.clone();
let (response, _) = index
.update_settings(json!({
"filterableAttributes": ["name_ja", "name_zh"],
"localizedAttributes": [
// force japanese
{"attributePatterns": ["*_ja", "*_zh"], "locales": ["jpn"]}
]
}))
.await;
snapshot!(response, @r###"
{
"taskUid": 0,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
index.add_documents(documents, None).await;
index.wait_task(1).await;
let (response, _) = index
.facet_search(json!({"facetName": "name_zh", "facetQuery": "进击", "locales": ["cmn"]}))
.await;
snapshot!(response, @r###"
{
"facetHits": [],
"facetQuery": "进击",
"processingTimeMs": "[duration]"
}
"###);
let (response, _) = index
.facet_search(json!({"facetName": "name_zh", "facetQuery": "进击", "locales": ["jpn"]}))
.await;
snapshot!(response, @r###"
{
"facetHits": [
{
"value": "进击的巨人",
"count": 1
}
],
"facetQuery": "进击",
"processingTimeMs": "[duration]"
}
"###);
let (response, _) =
index.facet_search(json!({"facetName": "name_zh", "facetQuery": "进击"})).await;
snapshot!(response, @r###"
{
"facetHits": [
{
"value": "进击的巨人",
"count": 1
}
],
"facetQuery": "进击",
"processingTimeMs": "[duration]"
}
"###);
}