Skip to content

Commit 9958a86

Browse files
authored
Merge branch 'federation' into implement-federated-multi-search
2 parents a826b64 + 7d0d3ee commit 9958a86

File tree

14 files changed

+1464
-81
lines changed

14 files changed

+1464
-81
lines changed

.code-samples.meilisearch.yaml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Every example written here will be automatically fetched by
33
# the documentation on build
44
# You can read more on https://github.com/meilisearch/documentation/tree/main/learn
5+
# See the original at https://github.com/meilisearch/documentation/blob/main/.code-samples.meilisearch.yaml
56
---
67
synonyms_guide_1: |-
78
let mut synonyms = std::collections::HashMap::new();
@@ -581,8 +582,12 @@ get_faceting_settings_1: |-
581582
.await
582583
.unwrap();
583584
update_faceting_settings_1: |-
585+
let mut facet_sort_setting = BTreeMap::new();
586+
facet_sort_setting.insert(String::from("*"), FacetSortValue::Alpha);
587+
facet_sort_setting.insert(String::from("genres"), FacetSortValue::Count);
584588
let mut faceting = FacetingSettings {
585589
max_values_per_facet: 2,
590+
sort_facet_values_by: Some(facet_sort_setting),
586591
};
587592
588593
let task: TaskInfo = client
@@ -1265,8 +1270,11 @@ getting_started_sorting: |-
12651270
.await
12661271
.unwrap();
12671272
getting_started_faceting: |-
1273+
let mut facet_sort_setting = BTreeMap::new();
1274+
facet_sort_setting.insert("*".to_string(), FacetSortValue::Count);
12681275
let mut faceting = FacetingSettings {
12691276
max_values_per_facet: 2,
1277+
sort_facet_values_by: Some(facet_sort_setting),
12701278
};
12711279
12721280
let task: TaskInfo = client
@@ -1663,6 +1671,69 @@ reset_proximity_precision_settings_1: |-
16631671
.reset_proximity_precision()
16641672
.await
16651673
.unwrap();
1674+
get_facet_search_settings_1: |-
1675+
let facet_search: bool = client
1676+
.index(INDEX_UID)
1677+
.get_facet_search()
1678+
.await
1679+
.unwrap();
1680+
update_facet_search_settings_1: |-
1681+
let task: TaskInfo = client
1682+
.index(INDEX_UID)
1683+
.set_facet_search(false)
1684+
.await
1685+
.unwrap();
1686+
reset_facet_search_settings_1: |-
1687+
let task: TaskInfo = client
1688+
.index(INDEX_UID)
1689+
.reset_facet_search()
1690+
.await
1691+
.unwrap();
1692+
get_prefix_search_settings_1: |-
1693+
let prefix_search: PrefixSearchSettings = client
1694+
.index(INDEX_UID)
1695+
.get_prefix_search()
1696+
.await
1697+
.unwrap();
1698+
update_prefix_search_settings_1: |-
1699+
let task: TaskInfo = client
1700+
.index(INDEX_UID)
1701+
.set_prefix_search(PrefixSearchSettings::Disabled)
1702+
.await
1703+
.unwrap();
1704+
reset_prefix_search_settings_1: |-
1705+
let task: TaskInfo = client
1706+
.index(INDEX_UID)
1707+
.reset_prefix_search()
1708+
.await
1709+
.unwrap();
1710+
facet_search_1: |-
1711+
let res = client.index("books")
1712+
.facet_search("genres")
1713+
.with_facet_query("fiction")
1714+
.with_filter("rating > 3")
1715+
.execute()
1716+
.await
1717+
.unwrap();
1718+
facet_search_2: |-
1719+
let mut facet_sort_setting = BTreeMap::new();
1720+
facet_sort_setting.insert("genres".to_string(), FacetSortValue::Count);
1721+
let faceting = FacetingSettings {
1722+
max_values_per_facet: 100,
1723+
sort_facet_values_by: Some(facet_sort_setting),
1724+
};
1725+
1726+
let res = client.index("books")
1727+
.set_faceting(&faceting)
1728+
.await
1729+
.unwrap();
1730+
facet_search_3: |-
1731+
let res = client.index("books")
1732+
.facet_search("genres")
1733+
.with_facet_query("c")
1734+
.execute()
1735+
.await
1736+
.unwrap();
16661737
get_search_cutoff_1: |-
16671738
let search_cutoff_ms: String = client
16681739
.index("movies")

.github/workflows/tests.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,36 @@ jobs:
8383
uses: ibiqlik/action-yamllint@v3
8484
with:
8585
config_file: .yamllint.yml
86+
87+
coverage:
88+
# Will not run if the actor is Dependabot (dependabot PRs)
89+
# Will not run if the event is a PR to bump-meilisearch-v* (so a pre-release PR)
90+
if: github.actor != 'dependabot[bot]' && !( github.event_name == 'pull_request' && startsWith(github.base_ref, 'bump-meilisearch-v') )
91+
runs-on: ubuntu-latest
92+
needs: integration_tests
93+
name: Code Coverage
94+
steps:
95+
- uses: actions/checkout@v4
96+
# Nightly Rust is used for cargo llvm-cov --doc below.
97+
- uses: dtolnay/rust-toolchain@nightly
98+
with:
99+
components: llvm-tools-preview
100+
- name: Install cargo-llvm-cov
101+
uses: taiki-e/install-action@v2
102+
with:
103+
tool: cargo-llvm-cov
104+
- name: Meilisearch (latest version) setup with Docker
105+
run: docker run -d -p 7700:7700 getmeili/meilisearch:latest meilisearch --no-analytics --master-key=masterKey
106+
- name: Collect coverage data
107+
# Generate separate reports for tests and doctests, and combine them.
108+
run: |
109+
set -euo pipefail
110+
cargo llvm-cov --no-report --all-features --workspace
111+
cargo llvm-cov --no-report --doc --all-features --workspace
112+
cargo llvm-cov report --doctests --codecov --output-path codecov.json
113+
- name: Upload coverage reports to Codecov
114+
uses: codecov/codecov-action@v5
115+
with:
116+
token: ${{ secrets.CODECOV_TOKEN }}
117+
files: codecov.json
118+
fail_ci_if_error: true

Cargo.toml

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,29 @@ resolver = "2"
1313
members = ["examples/*"]
1414

1515
[dependencies]
16-
async-trait = "0.1.51"
17-
iso8601 = "0.6.1"
18-
log = "0.4"
16+
async-trait = "0.1.88"
17+
iso8601 = "0.6.3"
18+
log = "0.4.27"
1919
serde = { version = "1.0", features = ["derive"] }
20-
serde_json = "1.0"
21-
time = { version = "0.3.7", features = ["serde-well-known", "formatting", "parsing"] }
20+
serde_json = "1.0.140"
21+
time = { version = "0.3.41", features = ["serde-well-known", "formatting", "parsing"] }
2222
yaup = "0.3.1"
23-
either = { version = "1.8.0", features = ["serde"] }
24-
thiserror = "1.0.37"
25-
meilisearch-index-setting-macro = { path = "meilisearch-index-setting-macro", version = "0.28.0" }
26-
pin-project-lite = { version = "0.2.13", optional = true }
27-
reqwest = { version = "0.12.3", optional = true, default-features = false, features = ["rustls-tls", "http2", "stream"] }
28-
bytes = { version = "1.6", optional = true }
29-
uuid = { version = "1.1.2", features = ["v4"] }
30-
futures-io = "0.3.30"
31-
futures = "0.3"
23+
either = { version = "1.15.0", features = ["serde"] }
24+
thiserror = "2.0.12"
25+
meilisearch-index-setting-macro.path = "meilisearch-index-setting-macro"
26+
pin-project-lite = { version = "0.2.16", optional = true }
27+
reqwest = { version = "0.12.22", optional = true, default-features = false, features = ["rustls-tls", "http2", "stream"] }
28+
bytes = { version = "1.10.1", optional = true }
29+
uuid = { version = "1.17.0", features = ["v4"] }
30+
futures-io = "0.3.31"
31+
futures = "0.3.31"
3232

3333
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
34-
jsonwebtoken = { version = "9", default-features = false }
34+
jsonwebtoken = { version = "9.3.1", default-features = false }
3535

3636
[target.'cfg(target_arch = "wasm32")'.dependencies]
37-
uuid = { version = "1.8.0", default-features = false, features = ["v4", "js"] }
38-
web-sys = "0.3"
37+
uuid = { version = "1.17.0", default-features = false, features = ["v4", "js"] }
38+
web-sys = "0.3.77"
3939
wasm-bindgen-futures = "0.4"
4040

4141
[features]
@@ -46,9 +46,9 @@ futures-unsend = []
4646
[dev-dependencies]
4747
futures-await-test = "0.3"
4848
futures = "0.3"
49-
mockito = "1.0.0"
49+
mockito = "1.0"
5050
meilisearch-test-macro = { path = "meilisearch-test-macro" }
51-
tokio = { version = "1", features = ["rt", "macros"] }
51+
tokio = { version = "1.46", features = ["rt", "macros"] }
5252

5353
# The following dependencies are required for examples
5454
wasm-bindgen = "0.2"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<a href="https://github.com/meilisearch/meilisearch-rust/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
2525
<a href="https://github.com/meilisearch/meilisearch/discussions" alt="Discussions"><img src="https://img.shields.io/badge/github-discussions-red" /></a>
2626
<a href="https://ms-bors.herokuapp.com/repositories/62"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></a>
27+
<a href="https://codecov.io/gh/meilisearch/meilisearch-rust"><img src="https://codecov.io/gh/meilisearch/meilisearch-rust/graph/badge.svg?token=NVO9OI8JMG"/></a>
2728
</p>
2829

2930
<p align="center">⚡ The Meilisearch API client written for Rust 🦀</p>

README.tpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<a href="https://github.com/meilisearch/meilisearch-rust/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
2525
<a href="https://github.com/meilisearch/meilisearch/discussions" alt="Discussions"><img src="https://img.shields.io/badge/github-discussions-red" /></a>
2626
<a href="https://ms-bors.herokuapp.com/repositories/62"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></a>
27+
<a href="https://codecov.io/gh/meilisearch/meilisearch-rust"><img src="https://codecov.io/gh/meilisearch/meilisearch-rust/graph/badge.svg?token=NVO9OI8JMG"/></a>
2728
</p>
2829

2930
<p align="center">⚡ The Meilisearch API client written for Rust 🦀</p>

meilisearch-index-setting-macro/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ repository = "https://github.com/meilisearch/meilisearch-rust"
1212
proc-macro = true
1313

1414
[dependencies]
15-
syn = { version = "2.0.48", features = ["extra-traits"] }
16-
quote = "1.0.21"
17-
proc-macro2 = "1.0.46"
18-
convert_case = "0.6.0"
15+
syn = { version = "2.0.104", features = ["extra-traits"] }
16+
quote = "1.0.40"
17+
proc-macro2 = "1.0.95"
18+
convert_case = "0.8.0"
1919
structmeta = "0.3"

meilisearch-test-macro/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ proc-macro = true
1010
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1111

1212
[dependencies]
13-
proc-macro2 = "1.0.0"
14-
quote = "1.0.0"
15-
syn = { version = "2.0.48", features = ["clone-impls", "full", "parsing", "printing", "proc-macro"], default-features = false }
13+
proc-macro2 = "1.0.95"
14+
quote = "1.0.40"
15+
syn = { version = "2.0.104", features = ["clone-impls", "full", "parsing", "printing", "proc-macro"], default-features = false }

src/client.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,10 +1149,17 @@ impl<Http: HttpClient> Client<Http> {
11491149
#[derive(Debug, Clone, Deserialize)]
11501150
#[serde(rename_all = "camelCase")]
11511151
pub struct ClientStats {
1152+
/// Storage space claimed by Meilisearch and LMDB in bytes
11521153
pub database_size: usize,
1154+
1155+
/// Storage space used by the database in bytes, excluding unused space claimed by LMDB
11531156
pub used_database_size: usize,
1157+
1158+
/// When the last update was made to the database in the `RFC 3339` format
11541159
#[serde(with = "time::serde::rfc3339::option")]
11551160
pub last_update: Option<OffsetDateTime>,
1161+
1162+
/// The statistics for each index found in the database
11561163
pub indexes: HashMap<String, IndexStats>,
11571164
}
11581165

src/indexes.rs

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,57 @@ impl<Http: HttpClient> Index<Http> {
279279
SearchQuery::new(self)
280280
}
281281

282+
/// Returns the facet stats matching a specific query in the index.
283+
///
284+
/// See also [`Index::facet_search`].
285+
///
286+
/// # Example
287+
///
288+
/// ```
289+
/// # use serde::{Serialize, Deserialize};
290+
/// # use meilisearch_sdk::{client::*, indexes::*, search::*};
291+
/// #
292+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
293+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
294+
/// #
295+
/// #[derive(Serialize, Deserialize, Debug)]
296+
/// struct Movie {
297+
/// name: String,
298+
/// genre: String,
299+
/// }
300+
/// # tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
301+
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
302+
/// let movies = client.index("execute_query2");
303+
///
304+
/// // add some documents
305+
/// # movies.add_or_replace(&[Movie{name:String::from("Interstellar"), genre:String::from("scifi")},Movie{name:String::from("Inception"), genre:String::from("drama")}], Some("name")).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
306+
/// # movies.set_filterable_attributes(["genre"]).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
307+
///
308+
/// let query = FacetSearchQuery::new(&movies, "genre").with_facet_query("scifi").build();
309+
/// let res = movies.execute_facet_query(&query).await.unwrap();
310+
///
311+
/// assert!(res.facet_hits.len() > 0);
312+
/// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
313+
/// # });
314+
/// ```
315+
pub async fn execute_facet_query(
316+
&self,
317+
body: &FacetSearchQuery<'_, Http>,
318+
) -> Result<FacetSearchResponse, Error> {
319+
self.client
320+
.http_client
321+
.request::<(), &FacetSearchQuery<Http>, FacetSearchResponse>(
322+
&format!("{}/indexes/{}/facet-search", self.client.host, self.uid),
323+
Method::Post { body, query: () },
324+
200,
325+
)
326+
.await
327+
}
328+
329+
pub fn facet_search<'a>(&'a self, facet_name: &'a str) -> FacetSearchQuery<'a, Http> {
330+
FacetSearchQuery::new(self, facet_name)
331+
}
332+
282333
/// Get one document using its unique id.
283334
///
284335
/// Serde is needed. Add `serde = {version="1.0", features=["derive"]}` in the dependencies section of your Cargo.toml.
@@ -484,7 +535,7 @@ impl<Http: HttpClient> Index<Http> {
484535
Error::MeilisearchCommunication(MeilisearchCommunicationError {
485536
status_code: error.status_code,
486537
url: error.url,
487-
message: Some(format!("{}.", MEILISEARCH_VERSION_HINT)),
538+
message: Some(format!("{MEILISEARCH_VERSION_HINT}.")),
488539
})
489540
}
490541
Error::Meilisearch(error) => Error::Meilisearch(MeilisearchError {
@@ -668,7 +719,7 @@ impl<Http: HttpClient> Index<Http> {
668719
self.add_or_replace(documents, primary_key).await
669720
}
670721

671-
/// Add a raw ndjson payload and update them if they already.
722+
/// Add a raw ndjson payload and update them if they already exist.
672723
///
673724
/// It configures the correct content type for ndjson data.
674725
///
@@ -760,7 +811,7 @@ impl<Http: HttpClient> Index<Http> {
760811
.await
761812
}
762813

763-
/// Add a raw csv payload and update them if they already.
814+
/// Add a raw csv payload and update them if they already exist.
764815
///
765816
/// It configures the correct content type for csv data.
766817
///
@@ -850,7 +901,7 @@ impl<Http: HttpClient> Index<Http> {
850901
.await
851902
}
852903

853-
/// Add a list of documents and update them if they already.
904+
/// Add a list of documents and update them if they already exist.
854905
///
855906
/// If you send an already existing document (same id) the old document will be only partially updated according to the fields of the new document.
856907
/// Thus, any fields not present in the new document are kept and remained unchanged.
@@ -1795,8 +1846,25 @@ impl<'a, Http: HttpClient> AsRef<IndexUpdater<'a, Http>> for IndexUpdater<'a, Ht
17951846
#[derive(Debug, Clone, Deserialize)]
17961847
#[serde(rename_all = "camelCase")]
17971848
pub struct IndexStats {
1849+
/// Total number of documents in an index
17981850
pub number_of_documents: usize,
1851+
1852+
/// Total number of documents with at least one embedding
1853+
pub number_of_embedded_documents: usize,
1854+
1855+
/// Total number of embeddings in an index
1856+
pub number_of_embeddings: usize,
1857+
1858+
/// Storage space claimed by all documents in the index in bytes
1859+
pub raw_document_db_size: usize,
1860+
1861+
/// Total size of the documents stored in an index divided by the number of documents in that same index
1862+
pub avg_document_size: usize,
1863+
1864+
/// If `true`, the index is still processing documents and attempts to search will yield impredictable results
17991865
pub is_indexing: bool,
1866+
1867+
/// Shows every field in the index along with the total number of documents containing that field in said index
18001868
pub field_distribution: HashMap<String, usize>,
18011869
}
18021870

src/key.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ impl AsRef<KeyBuilder> for KeyBuilder {
651651
}
652652
}
653653

654-
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
654+
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
655655
pub enum Action {
656656
/// Provides access to everything.
657657
#[serde(rename = "*")]
@@ -713,6 +713,13 @@ pub enum Action {
713713
/// Provides access to the [delete key](https://www.meilisearch.com/docs/reference/api/keys#delete-a-key) endpoint.
714714
#[serde(rename = "keys.delete")]
715715
KeyDelete,
716+
/// Provides access to chat completions endpoints.
717+
#[serde(rename = "chatCompletions")]
718+
ChatCompletions,
719+
/// Any other value that might be added to Meilisearch in the future but that is not supported by this SDK.
720+
/// If you see one, please open a PR
721+
#[serde(untagged)]
722+
Unknown(String),
716723
}
717724

718725
#[derive(Debug, Clone, Deserialize)]

0 commit comments

Comments
 (0)