Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 88 additions & 94 deletions .code-samples.meilisearch.yaml

Large diffs are not rendered by default.

70 changes: 59 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ NB: you can also download MeiliSearch from **Homebrew** or **APT**.

## 🚀 Getting Started

#### Add Documents <!-- omit in TOC -->

```rust
use meilisearch_sdk::{document::*, client::*, search::*};
use meilisearch_sdk::{document::*, client::*};
use serde::{Serialize, Deserialize};
use futures::executor::block_on;

Expand All @@ -110,10 +112,10 @@ fn main() { block_on(async move {
// Create a client (without sending any request so that can't fail)
let client = Client::new("http://localhost:7700", "masterKey");

// Get the index called "movies"
let movies = client.get_or_create("movies").await.unwrap();
// An index is where the documents are stored.
let movies = client.index("movies");

// Add some movies in the index
// Add some movies in the index. If the index 'movies' does not exist, MeiliSearch creates it when you first add the documents.
movies.add_documents(&[
Movie{id: 1, title: String::from("Carol"), genres: vec!["Romance".to_string(), "Drama".to_string()]},
Movie{id: 2, title: String::from("Wonder Woman"), genres: vec!["Action".to_string(), "Adventure".to_string()]},
Expand All @@ -122,19 +124,64 @@ fn main() { block_on(async move {
Movie{id: 5, title: String::from("Moana"), genres: vec!["Fantasy".to_string(), "Action".to_string()]},
Movie{id: 6, title: String::from("Philadelphia"), genres: vec!["Drama".to_string()]},
], Some("id")).await.unwrap();

// Query movies (note that there is a typo)
println!("{:?}", movies.search().with_query("carol").execute::<Movie>().await.unwrap().hits);
})}
```

Output:
#### Basic Search <!-- omit in TOC -->

```rust
// MeiliSearch is typo-tolerant:
println!("{:?}", client.index("movies").search().with_query("caorl").execute::<Movie>().await.unwrap().hits);
```

Output:
```
[Movie{id: 1, title: String::from("Carol"), genres: vec!["Romance", "Drama"]}]
```

##### Custom Search With Filters <!-- omit in TOC -->
Json output:
```json
{
"hits": [{
"id": 1,
"title": "Carol",
"genres": ["Romance", "Drama"]
}],
"offset": 0,
"limit": 10,
"processingTimeMs": 1,
"query": "caorl"
}
```

#### Custom Search <!-- omit in toc -->

```rust
println!("{:?}", client.index("movies").search().with_query("phil").with_attributes_to_highlight(Selectors::Some(&["*"])).execute::<Movie>().await.unwrap().hits);
```

Json output:
```json
{
"hits": [
{
"id": 6,
"title": "Philadelphia",
"_formatted": {
"id": 6,
"title": "<em>Phil</em>adelphia",
"genre": ["Drama"]
}
}
],
"offset": 0,
"limit": 20,
"processingTimeMs": 0,
"query": "phil"
}
```

#### Custom Search With Filters <!-- omit in TOC -->

If you want to enable filtering, you must add your attributes to the `filterableAttributes`
index setting.
Expand All @@ -144,7 +191,7 @@ let filterable_attributes = [
"id",
"genres"
];
movies.set_filterable_attributes(&filterable_attributes).await.unwrap();
client.index("movies").set_filterable_attributes(&filterable_attributes).await.unwrap();
```

You only need to perform this operation once.
Expand All @@ -157,10 +204,11 @@ status](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-st
Then, you can perform the search:

```rust
println!("{:?}", movies.search().with_query("wonder").with_filter("id > 1 AND genres = Action")
println!("{:?}", client.index("movies").search().with_query("wonder").with_filter("id > 1 AND genres = Action")
.execute::<Movie>().await.unwrap().hits);
```

Json output:
```json
{
"hits": [
Expand Down
4 changes: 2 additions & 2 deletions examples/web_app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ impl Component for Model {
Self {
link: Rc::new(link),

// The assume_index method avoids checking the existence of the index.
// The index method avoids checking the existence of the index.
// It won't make any HTTP request so the function is not async so it's easier to use.
// Use only if you are sure that the index exists.
index: Rc::new(CLIENT.assume_index("crates")),
index: Rc::new(CLIENT.index("crates")),
results: Vec::new(),
processing_time_ms: 0,

Expand Down
58 changes: 47 additions & 11 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl Client {
Ok(json_indexes)
}

/// Get an [index](../indexes/struct.Index.html).
/// Get an [index](../indexes/struct.Index.html), this index should already exist.
///
/// # Example
///
Expand All @@ -104,7 +104,7 @@ impl Client {
}
}

/// Get a raw JSON [index](../indexes/struct.Index.html).
/// Get a raw JSON [index](../indexes/struct.Index.html), this index should already exist.
///
/// # Example
///
Expand All @@ -120,17 +120,13 @@ impl Client {
/// let movies = client.get_raw_index("movies").await.unwrap();
/// # });
/// ```
/// If you use it directly from an index, you can use the method [fetch_info](#method.fetch_info), which is the equivalent method from an index.
pub async fn get_raw_index(&self, uid: impl AsRef<str>) -> Result<JsonIndex, Error> {
Ok(request::<(), JsonIndex>(
&format!("{}/indexes/{}", self.host, uid.as_ref()),
&self.api_key,
Method::Get,
200,
).await?)
Index::fetch_info(&self.index(uid.as_ref())).await
}

/// Assume that an [index](../indexes/struct.Index.html) exist and create a corresponding object without any check.
pub fn assume_index(&self, uid: impl Into<String>) -> Index {
/// Create a corresponding object of an [index](../indexes/struct.Index.html) without any check or doing an HTTP call.
pub fn index(&self, uid: impl Into<String>) -> Index {
Index {
uid: Rc::new(uid.into()),
host: Rc::clone(&self.host),
Expand Down Expand Up @@ -383,7 +379,18 @@ mod tests {
#[async_test]
async fn test_get_keys() {
let client = Client::new("http://localhost:7700", "masterKey");
client.get_keys().await.unwrap();
let keys = client.get_keys().await.unwrap();
assert!(keys.private.is_some());
assert!(keys.public.is_some());
}

#[async_test]
async fn test_get_index() {
let client = Client::new("http://localhost:7700", "masterKey");
let index_name = "get_index";
client.create_index(index_name, None).await.unwrap();
let index = client.get_index(index_name).await.unwrap();
assert_eq!(index.uid.to_string(), index_name);
}

#[async_test]
Expand Down Expand Up @@ -431,4 +438,33 @@ mod tests {
let deleted = client.delete_index_if_exists("bad").await.unwrap();
assert_eq!(deleted, false);
}

#[async_test]
async fn test_fetch_info() {
let client = Client::new("http://localhost:7700", "masterKey");
let index_name = "fetch_info";
client.create_index(index_name, None).await.unwrap();
let index = client.index(index_name).fetch_info().await;
assert!(index.is_ok());
}

#[async_test]
async fn test_get_primary_key_is_none() {
let client = Client::new("http://localhost:7700", "masterKey");
let index_name = "get_primary_key_is_none";
client.create_index(index_name, None).await.unwrap();
let primary_key = client.index(index_name).get_primary_key().await;
assert!(primary_key.is_ok());
assert!(primary_key.unwrap().is_none());
}

#[async_test]
async fn test_get_primary_key() {
let client = Client::new("http://localhost:7700", "masterKey");
let index_name = "get_primary_key";
client.create_index(index_name, Some("primary_key")).await.unwrap();
let primary_key = client.index(index_name).get_primary_key().await;
assert!(primary_key.is_ok());
assert_eq!(primary_key.unwrap().unwrap(), "primary_key");
}
}
Loading