GithubHelp home page GithubHelp logo

meilisearch / meilisearch-rust Goto Github PK

View Code? Open in Web Editor NEW
320.0 11.0 82.0 1.43 MB

Rust wrapper for the Meilisearch API.

Home Page: https://www.meilisearch.com

License: MIT License

Rust 99.50% Shell 0.50%
rust search-engine sdk meilisearch crate wasm

meilisearch-rust's People

Contributors

abhizer avatar alallema avatar amaihoefner avatar bidoubiwa avatar bors[bot] avatar brunoocasali avatar carlosb1 avatar curquiza avatar dependabot[bot] avatar evpeople avatar ginglis13 avatar hmacr avatar icyjoseph avatar irevoire avatar isaaccloos avatar khanhnt2 avatar korir248 avatar meili-bors[bot] avatar meili-bot avatar mk1107 avatar mubelotix avatar noodlesamachan avatar omid avatar puddingpy avatar romilpunetha avatar sanders41 avatar shimatar0 avatar ugzuzg avatar vishalsodani avatar washbin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meilisearch-rust's Issues

Error with ProcessedStatus

I was looking at the possibility of adding the get all update status route in #39 and have run into an issue. According to the documentation the response will look like:

[
  {
    "status": "processed",
    "updateId": 1,
    "type": {
      "name": "DocumentsAddition",
      "number": 4
    },
    "duration": 0.076980613,
    "enqueuedAt": "2019-12-07T21:16:09.623944Z",
    "processedAt": "2019-12-07T21:16:09.703509Z"
  }
]

but when I test I get an error ParseError(Error("missing field `duration`", line: 1, column: 325). This error seems to resolve and the response does include the duration and processedAt information if I do sleep(Duration::from_secs(1)); after adding documents.

I checked what response I get in the python clients test and the result in the test is:

[
    {
        'status': 'enqueued', 
        'updateId': 0,
        'type': {
            'name': 'DocumentsAddition',
            'number': 30
        },
        'enqueuedAt': '2021-02-14T14:07:09.364505700Z'
    },
    {
        'status': 'enqueued',
        'updateId': 1,
        'type': {
             'name': 'DocumentsAddition',
             'number': 30
        },
        'enqueuedAt': '2021-02-14T14:07:09.373833600Z'
    }
]

Since Python is putting the information into a dictionary the tests passes, but if the end user is expecting the keys to be there and used, for example, result["duration"] instead of result.get("duration") this would error.

My guess is that in the documentation it is assuming that the documents will always be processed before checking the status, but this doesn't seem to be the case? If that is correct would updating ProcessedStatus to the following be appropriate?

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ProcessedStatus {
    pub update_id: u64,
    #[serde(rename = "type")]
    pub update_type: UpdateType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub duration: Option<f64>,        // in seconds
    pub enqueued_at: String,  // TODO deserialize to datatime
    #[serde(skip_serializing_if = "Option::is_none")]
    pub processed_at: Option<String>, // TODO deserialize to datatime
}

Also, if this is the case should the documentation be updated to note that these fields are optional in the response since it would affect all clients even if they don't error?

Make each test independent

To avoid side effects between each test, the tests should all be independent.

It means, at the beginning of each test:

  • create the needed index(es)
  • push documents according to the test
  • update settings if necessary

And at the end of each test:

  • remove the index(es)

This is linked to #29

Examples section

Currently, and even after this PR #32 that installs all the process to generate the README, the examples section is still empty. Only the Getting Started example is tested and generated.

A lot of tests have been written by @Mubelotix, and we should find a way to generate them as well in the Examples section.

Don't require tokio runtime

Currently, this project requires usage of the tokio runtime, using it with f.e. async-std is not possible. It would be nice if we could also use it with these other runtimes, without having to do this (yuck):

    tokio::runtime::Builder::new()
        .basic_scheduler()
        .enable_all()
        .build()?
        .block_on(do_something_async())?;

As far as i can see, the only reason is the dependency of reqwest.

Switching to a runtime-agnostic http client seems possible. I made out https://github.com/http-rs/surf as a good option, especially since it has a wasm-backend. One should probably wait for its 2.0 release before switching.

Remove indexes after running the tests

When running the tests, we create indexes in the MeiliSearch instances, but we don't remove them once the tests have finished.
It leads to tests failure when I relaunch the tests with the same MeiliSearch instance, not really convenient for development purpose ๐Ÿ™‚

Use a masterKey for the tests

Currently, the tests only work with a MeiliSearch instance running without any master-key.

The tests should work with a MeiliSearch instance running with a master key named masterKey, launched this way:

$ docker run -it --rm -p 7700:7700 getmeili/meilisearch:v0.12.0 ./meilisearch  --no-analytics=true --master-key=masterKey

Use slices (&[T]) instead of references to a vector (&Vec<T>) in the documents API

Currently the documents API on master takes &Vec<T> parameters when adding or deleting documents. Slices (&[T]) are more idiomatic while providing the same functionality. Making the parameter a slice allows more flexibility for the users of the API, and can allow the API to be used with arrays and other data structures besides Vecs.

I can also make a PR with this change if that would be helpful.

Broken on Meilisearch v0.11

As the title says, when using this SDK on 0.11 the thread panics with this error:

thread 'main' panicked at 'called Result::unwrap()on anErr value: Unknown("{\"message\":\"Unsupported media type\",\"errorCode\":\"unsupported_media_type\",\"errorType\":\"invalid_request_error\",\"errorLink\":\"https://docs.meilisearch.com/error/unsupported_media_type\"}")', src/routes/search.rs:184:31 stack backtrace:

Meilisearch SDK can give strange errors when running against newer meilisearch versions

Description
I am using meilisearch-sdk = "0.9.0" against main of meilisearch (63daa8b15ab21d).

When I create an index and unwrap with client.create_index("param_types", None).await.unwrap(), I get this error:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: MeiliSearchError { message: "{\"uid\":\"param_types\",\"name\":\"param_types\",\"createdAt\":\"2021-08-10T23:00:32.580595725Z\",\"updatedAt\":\"2021-08-10T23:00:32.5805
95725Z\",\"primaryKey\":null}", error_code: Unknown("missing errorCode"), error_type: Internal, error_link: "" }', src/lib.rs:175:74

Expected behavior
If there is version incompatibility, meilisearch fails in some obvious way.

Current behavior
I was presented with an opaque error message that gave no indication about cause or resolution.

Environment (please complete the following information):

  • OS: Ubuntu 18.04
  • MeiliSearch version: 63daa8b15ab21d
  • meilisearch-rust version: 0.9.0

Improve the README

The README should have the same template as the other SDKs, but stay consistent with the Rust necessities of the language, of course.

The README should contain at least:

  • A table of content
  • An installation section
  • A Getting Started section
  • An Examples sections (with search, indexes manipulation, documents manipulation and updates)
  • A Development Workflow and Contributing section that redirect to a CONTRIBUTING.md file (see this issue #8)
  • A footer (see the README below)
  • All other needed sections (WASM, How to generate the docs if present...)

Should be highly inspired by this README

Update to tokio 1.0

Reqwest is now using tokio 1.0 (seanmonstar/reqwest#1076 was merged), so I think the update could be done now ?

EDIT: Actually I just figured out that even if it has been merged into master, not tag were added.

Unexpected test failure

The test progress::test::test_wait_for_pending_updates_time_out randomly fails in rare cases.

Missing and broken links

The crates.io and docs.rs pages are both missing a repository link and the wasm tutorial isn't pointing to anything

Improve Query and SearchResults

Query:

  • Add the matches option
  • Change attributes_to_crop into a Vec
  • Change attributes_to_highlight into a Vec
  • Change attributes_to_retrieve into a Vec

Results:

  • Support matches_info
  • Support formatted results

Create and fill sample file to display Rust examples in MeiliSearch Documentation

Code Samples for MeiliSearch documentation

Introduction

As MeiliSearch grows so does its SDK's. More and more SDK's rises from the ground and they all deserve to be as well documented as the core engine itself.

The most common way for a user to understand MeiliSearch is to go to its official documentation. As of yesterday all examples in the documentation were made with cURL. Unfortunately, most of our users do not communicate with MeiliSearch directly with cURL. Which forces them to search for the specific references somewhere else (in the readme's, in the sdk's code itself,..). This makes for unnecessary friction.

Goal

We want our documentation to include all SDK's

As a first step we want all examples to be made using the most possible SDK's. As did Stripe and Algolia.

sdk_sample

examples with curl, javascript and soon enough this SDK too!

To achieve this it is expected from this SDK to create a sample file containing all the code samples needed by the documentation.

These are the steps to follow:

  • Create your sample file
  • Fill your sample file
  • Add your samples to the documentation

Create your sample file

The sample file is a yaml file added at the root of each MeiliSearch SDK.
Sample files are created based on the sample-template.yaml file.

sample-template file:

get_one_index_1: |-
list_all_indexes_1: |-
create_an_index_1: |-
...

This template is accessible publicly here or in the public directory : .vuepress/public/sample-template.yaml of the documentation.

The name of the file should be .code-samples.meilisearch.yaml

Fill your sample file

After creating the sample file with the content of the sample template you should have a file containing all the sampleId's.

get_one_index_1: |-
list_all_indexes_1: |-
create_an_index_1: |-
...

By the name of the different sampleId you should know where that code sample will be added to the documentation.

For example, create_an_index_1 is the first example in the API References of the index creation.

Using the already existing cURL example in the documentation you should see what is expected from that sample. It is very important that you look at the already existing samples in the documentation as it gives you the parameters to use in your sample to match with the rest of the documentation.

Good sample based on documentation:

create_an_index_1: |-
  client.createIndex({ uid: 'movies' })

Bad sample that does not match with the response.

create_an_index_1: |-
  client.createIndex({ uid: 'otherName' })

Each sample is expected to be written in the respective SDK language.

Javascript example:

get_one_index_1: |-
  client.getIndex('movies').show()
list_all_indexes_1: |-
  client.listIndexes()
create_an_index_1: |-
  client.createIndex({ uid: 'movies' })
  ...

The complete cURL sample file is available at the root of the documentation repository.
Every other SDK sample file should be available at the root of their respective repository.

Formatting Exception

There is one exception to the formatting rule.
When the sampleId finishes with _md it means it is expected to be written in markdown format.

JavaScript sample id with _md extension:
yaml-js-example

Add your samples to the documentation

Once your sample file is filled with the code samples, you will need to create a pull request on the documentation repository.

Open the following file in your IDE:
.vuepress/code-samples/sdks.json

And add your sample file to the list:

[
  ...
  {
    "language": "sdk-language",
    "label": "sdk-label",
    "url": "url to yaml file"
  }
]

The language key expect a supported language for the code highlight.

The label key is the name of the tab. While label and language could have been the same, it created some conflict (i.e: bash and cURL).

The url is the raw link to access your sample file. It should look like this:
https://raw.githubusercontent.com/[PROJECT]/[REPO]/.code-samples.meilisearch.yaml

Consider using macros

Macros are a wonderful feature of the Rust language that could help us for 2 things :

Add an abstraction over the Document trait

We currently use a Document trait to make structures of users compatible with MeiliSearch.
It works great but has some unpleasant boilerplate code.

Examples

Currently

#[derive(Debug, Serialize, Deserialize)]
pub struct Crate {
    name: String,
    downloads: Option<usize>,
    description: String,
    keywords: Vec<String>,
    categories: Vec<String>,
    readme: String,
    version: String,
}

// Implement the Document trait so that we can use our struct with MeiliSearch
impl Document for Crate {
    type UIDType = String;

    fn get_uid(&self) -> &Self::UIDType {
        &self.name
    }
}

With macros

#[derive(Debug, Serialize, Deserialize, MeiliSearchDocument)]
pub struct Crate {
    #[primary_key]
    name: String,
    downloads: Option<usize>,
    description: String,
    keywords: Vec<String>,
    categories: Vec<String>,
    readme: String,
    version: String,
}

Simplify our tests

There are currently issues about tests in this library. They are many but they are not standardized enough. This is a pain point when it comes to maintain existing tests and adding new ones.
We could use macros to generate tests.

Examples

Currently (unit test)

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Document {
        id: usize,
        value: String,
        kind: String,
    }

    impl document::Document for Document {
        type UIDType = usize;

        fn get_uid(&self) -> &Self::UIDType {
            &self.id
        }
    }

    #[allow(unused_must_use)]
    async fn setup_test_index<'a>(client: &'a Client<'a>, name: &'a str) -> Index<'a> {
        // try to delete
        client.delete_index(name).await;

        let index = client.create_index(name, None).await.unwrap();
        index.add_documents(&[
            Document { id: 0, kind: "text".into(), value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.".to_string() },
            Document { id: 1, kind: "text".into(), value: "dolor sit amet, consectetur adipiscing elit".to_string() },
            Document { id: 2, kind: "title".into(), value: "The Social Network".to_string() },
            Document { id: 3, kind: "title".into(), value: "Harry Potter and the Sorcerer's Stone".to_string() },
            Document { id: 4, kind: "title".into(), value: "Harry Potter and the Chamber of Secrets".to_string() },
            Document { id: 5, kind: "title".into(), value: "Harry Potter and the Prisoner of Azkaban".to_string() },
            Document { id: 6, kind: "title".into(), value: "Harry Potter and the Goblet of Fire".to_string() },
            Document { id: 7, kind: "title".into(), value: "Harry Potter and the Order of the Phoenix".to_string() },
            Document { id: 8, kind: "title".into(), value: "Harry Potter and the Half-Blood Prince".to_string() },
            Document { id: 9, kind: "title".into(), value: "Harry Potter and the Deathly Hallows".to_string() },
        ], None).await.unwrap();
        index.set_attributes_for_faceting(["kind"]).await.unwrap();
        sleep(Duration::from_secs(1));
        index
    }

    #[async_test]
    async fn test_query_string() {
        let client = Client::new("http://localhost:7700", "masterKey");
        let index = setup_test_index(&client, "test_query_string").await;

        let results: SearchResults<Document> =
            index.search().with_query("dolor").execute().await.unwrap();
        assert_eq!(results.hits.len(), 2);

        client.delete_index("test_query_string").await.unwrap();
    }

With macros (unit test)

    #[meilisearch_test]
    async fn test_query_string() {
        let results: SearchResults<Document> =
            index.search().with_query("dolor").execute().await.unwrap();
        assert_eq!(results.hits.len(), 2);
    }

Currently (doc test)
    /// ```
    /// # use meilisearch_sdk::{client::*, indexes::*};
    /// # futures::executor::block_on(async move {
    /// // create the client
    /// let client = Client::new("http://localhost:7700", "masterKey");
    ///
    /// let indexes: Vec<Index> = client.list_all_indexes().await.unwrap();
    /// println!("{:?}", indexes);
    /// # });
    /// ```

With macros (doc test)
    /// ```
    /// # #[meilisearch_doctest]
    /// # fn test() {
    /// let indexes: Vec<Index> = client.list_all_indexes().await.unwrap();
    /// println!("{:?}", indexes);
    /// # }
    /// ```

The problem with macros

Rust does not allow us to define macros in a regular crate. We would need to create a new crate that would contain macros. That could cause extra maintenance work in the future, but it should not be necessary to update macros often.

Change master branch to main

Let's be allies and make this change that means a lot.

Here is a blog post that explain a little more why it's important, and how to easily do it. It will be a bit more complicated with automation, but we still should do it!

Crash when following Example step by step

Hey, unlike my previous issue I have followed the examples step by step.

I have setup a MeiliSearch server, and used this rust application code:

use meilisearch_sdk::{document::*, indexes::*, client::*, search::*};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Book {
    book_id: usize,
    title: String,
}

// That trait is required to make a struct usable by an index
impl Document for Book {
    type UIDType = usize;

    fn get_uid(&self) -> &Self::UIDType {
        &self.book_id
    }
}

fn main() {
    // Create a client (without sending any request so that can't fail)
    let client = Client::new("http://localhost:7700", "");

// Get the index called "books"
    let mut books = client.get_or_create("books").unwrap();

// Add some books in the index
    books.add_documents(vec![
        Book{book_id: 123,  title: String::from("Pride and Prejudice")},
        Book{book_id: 456,  title: String::from("Le Petit Prince")},
        Book{book_id: 1,    title: String::from("Alice In Wonderland")},
        Book{book_id: 1344, title: String::from("The Hobbit")},
        Book{book_id: 4,    title: String::from("Harry Potter and the Half-Blood Prince")},
        Book{book_id: 42,   title: String::from("The Hitchhiker's Guide to the Galaxy")},
    ], Some("book_id")).unwrap();

// Query books (note that there is a typo)
    let query = Query::new("harry pottre");
    println!("{:?}", books.search::<Book>(&query).unwrap().hits);
}

I am still getting a crash!
Here is the crash:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Unknown("null")', src/main.rs:24:21
stack backtrace:```

Are lifetimes really required?

I am facing difficulty to write a script using this library due to self-referential structs in given for the code below:

use meilisearch_sdk::{document::*, client::*, search::*};
use meilisearch_sdk::indexes::Index;
use serde::{Serialize, Deserialize};
use serde_json::{Deserializer, Value};
use futures::executor::block_on;
use std::fs::File;
use read_iter::ReadIter; // also add dependency to Cargo.toml
use nop_json::{Reader, TryFromJson, ValidateJson, DebugToJson};
use futures::lock::Mutex;
use std::sync::Arc;

#[derive(TryFromJson, ValidateJson, DebugToJson, PartialEq, Serialize, Deserialize)]
struct User {
    id: usize,
    email: String,
    role: String,
    first_name: String,
    middle_name: String,
    last_name: String,
}

// That trait is required to make a struct usable by an index
impl Document for User {
    type UIDType = usize;

    fn get_uid(&self) -> &Self::UIDType {
        &self.id
    }
}

struct MeiliSearchClient<'a>  {
    client: Client<'a>,
    index: Option<Index<'a>>,
}

impl<'a> MeiliSearchClient<'a> {

    fn new() -> Self {
        MeiliSearchClient {
            client: Client::new("http://localhost:7700", "masterKey"),
            index: None,
        }
    }

    async fn process(&mut self, payload: &Vec<User>) {
        if !self.index.is_none() {
            self.index = Some(self.client.get_or_create("users").await.unwrap());
        }
        self.index
            .as_ref()
            .unwrap()
            .add_documents(payload, Some("id"))
            .await
            .unwrap();
    }

}

fn main() {

    let file = File::open("users.json").unwrap();
    let mut iter = ReadIter::new(file);
    let mut reader = Reader::new(&mut iter);

    let mut client = Arc::new(Mutex::new(MeiliSearchClient::new()));

    let mut payload: Vec<User> = Vec::with_capacity(1000);

    reader.read_array(|reader| {

        match reader.read::<User>() {

            Ok(value) => {
                payload.push(value);
                if payload.len() == 1000 {
                    let client_clone = Arc::clone(&client);
                    let payload_ref = &payload;
                    block_on(async move {
                        let mut client_locked = client_clone.lock().await;
                        client_locked.process(payload_ref).await;
                    });
                    payload.clear();
                }
            },
            Err(e) => {
                println!("{}", e);
                // block_on(async move {
                //     let mut client = client.lock().await;
                //     client.process(payload_ref).await;
                // });
                payload.clear();
            },
        }
        Ok(())
    }).unwrap();

}

It will not compile. Note that the problem is around the definition of the Meilisearch manager struct:

struct MeiliSearchClient<'a>  {
    client: Client<'a>,
    index: Option<Index<'a>>, //<---- Problem here
}

I do understand that the requirement for the lifetimes is due to the client instance inside the Index struct, but in general, this seems to be a non-ideal solution for an async API.

Any idea of what can be done in this example? I can see that the Client reference is only needed to retrieve the host and apiKey. Would be nice to migrate this into a Config struct that can be shared between these routes?

Regards!
Pedro

waitForPendingUpdate method

The wait_for_pending_update method is a method to wait for the asynchronous update of MeiliSearch (like update/reset the settings or add/update/delete documents).
This method is really useful for testing phases: you add documents, you wait for the document update to finish, you check all the documents have been added. This is also used by users who wanted to work synchronously.

Details of the method

  • This method is a loop that checks the status of the update every interval until a timeout.
    Both parameters (interval and timeout) must be:

    • customizable by the user.
    • optional and the method should set default values if they are not defined by the user.
      interval: 50ms
      timeout: 5 seconds
  • If the method times out, it should return a TimeOut Exception.

Example

In the PHP SDK
https://github.com/meilisearch/meilisearch-php/blob/b6e588d739f78071d9361d4eea9b05764f22877b/src/Endpoints/Indexes.php#L104-L116

Steps

  • add in the code
  • tests

Update documentation

Update the docs to finalize the tokio removal. See #70

Make the PR pointing to the isahc-dev branch

WASM Build In CI

Related to issue #135, since none of the test suite runs against the WASM build would it be worth it to add a WASM build step in the way an end user would build it to the CI tests? Since there are areas of the code that only compile and run if the build is for WASM these currently never get tested.

If yes maybe also add it as a test to run with the same settings in the contributing guide?

Testing against populated data

Summary

When running cargo test I noticed that I need to have a Meilisearch instance pre-configured before hand. This instance generally is empty and the tests are not running against a populated instance, no assert is done regarding the data that the SDK returns.

Possible solution

I would suggest to add a pre-setup configuration for the command cargo test, this is possible with the runner cargo-make: https://sagiegurari.github.io/cargo-make/

Add CI to run the tests

Run a CI that launches the tests for each PR and on master.

A PR that does not pass the tests has to be refused

Settings can only store owned data

The Settings struct is using Vecs and Strings, which are owned structures.
It should also be able to use borrowed values.
We should replace these owned types by generics (but since there is many fields it would make a lot of generics ๐Ÿ˜ฌ).

Add clippy to the CI

Clippy is the linter used in the MeiliSearch repo, and allows better contributions and maintenance ๐Ÿ™‚

A PR that does not pass clippy should be refused.

Missing routes

The Get Keys and Get all update status routes are still missing. It can be useful in rare cases.

Error enum doesn't implement std::error::Error

The error enum meilisearch_sdk::errors::Error doesn't implement std::error::Error, which makes it hard to integrate with other error handling systems such as thiserror and anyhow. All it should require are Display and Error impls for the Error enum.

For better compatibility, it would also be useful to add an enum variant for reqwest errors, so that the source method can be implemented on the Error enum. That would be a breaking change though, so it may be worth delaying until a 0.2 release is ready.

Remove the warning

The warning should be removed

$ cargo build
warning: unused import: `settings::*`
 --> src/indexes.rs:2:85
  |
2 |     client::Client, document::*, errors::Error, progress::*, request::*, search::*, settings::*,
  |                                                                                     ^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.08s

This warning also appears during the tests launch

Crash when following example

Hey, I have followed the example and my application is crashing! Here is the crash report:
thread 'main' panicked at 'called Result::unwrap() on an Err value: UnreachableServer', src/main.rs:91:20
stack backtrace:

Am I doing something wrong?

Support Meilisearch v0.12 errors

Currently, this library uses string matching on the JSON errors to determine the error type, as Meilisearch only returned a message, and no error code. Meilisearch v0.12 adds an errorCode field to the error JSON, which should allow for better forwards compatibility with the future, in case of changes in the human readable message. Since the current method relies entirely on string parsing, adding new fields to the JSON error breaks it. I have a fixed implementation here, but there are many error types that need to be added.

impl From<&serde_json::Value> for Error {
    fn from(message: &serde_json::Value) -> Error {
        // Error codes from https://github.com/meilisearch/MeiliSearch/blob/v0.12.0/meilisearch-error/src/lib.rs
        match message.get("errorCode").and_then(|v| v.as_str()) {
            Some("index_not_found") => Error::IndexNotFound,
            Some("index_already_exists") => Error::IndexAlreadyExist,
            Some("invalid_index_uid") => Error::InvalidIndexUid,
            Some("missing_primary_key") => Error::CantInferPrimaryKey,
            Some("maintenance") => Error::ServerInMaintenance,
            Some(_) => Error::Unknown(message.to_string()),
            None => {
                // Meilisearch 0.11 and below 
                match message.get("message").and_then(|v| v.as_str()) {
                    Some("Impossible to create index; index already exists") => Error::IndexAlreadyExist,
                    Some("Could not infer a primary key") => Error::CantInferPrimaryKey,
                    Some(m) if m.starts_with("Server is in maintenance, please try again later") => Error::ServerInMaintenance,
                    Some(m) if m.starts_with("Index ") && m.ends_with(" not found") => Error::IndexNotFound,
                    Some(m) if m.starts_with("Index must have a valid uid;") => Error::InvalidIndexUid,
                    _ => {
                        Error::Unknown(message.to_string())
                    },
                }
            }
        }
    }
}

I am using https://github.com/meilisearch/MeiliSearch/blob/v0.12.0/meilisearch-error/src/lib.rs as a source for the error codes, as the Meilisearch documentation does not currently have a list.

WASM Build Error

Someone on the Slack channel pointed out he is getting a build error when compiling to WASM.

Compiling meilisearch-sdk v0.7.0 (X:\Work\meilisearch-rust-0.7.0)
error[E0599]: no method named `try_into` found for type `u128` in the current scope
   --> src\progress.rs:152:38
    |
152 |                 interval.as_millis().try_into().unwrap(),
    |                                      ^^^^^^^^ method not found in `u128`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use std::convert::TryInto;`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
error: could not compile `meilisearch-sdk`
To learn more, run the command again with --verbose.
Error: Compiling your crate to WebAssembly failed
Caused by: failed to execute `cargo build`: exited with exit code: 101
  full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"

The error happens here. When I compile with the test compile from the docs, cargo build --example web_app, I don't get an error, but if I compile like he compiled, cargo build --lib --release --target wasm32-unknown-unknown I get the same error.

I tested changing the interval line to interval.as_millis() I get an error to change it to interval.as_millis().try_into().unwrap() which is what is already there.

rror[E0308]: mismatched types
   --> src/progress.rs:152:17
    |
152 |                 interval.as_millis(),
    |                 ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u128`
    |
help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit
    |
152 |                 interval.as_millis().try_into().unwrap(),
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Making indexes generic over the contained document type

I think the way this library handles Document types can be improved.

Current implementation

The type of the Document must be explicitly specified at each request.

let books = client.get_index("books").await?;
let results = books.search().with_query("harry pottre").execute::<Book>().await?;

That is very flexible but do we really need flexibility here? The type of the document will (and should) almost never change at runtime.
The current solution may lead to bugs where the actual type of the Index does not match the specified type of the request.

let index = client.get_index("books").await?;
let book_results = index.search().with_query("harry pottre").execute::<Book>().await?;

// some code

let movie_results = index.search().with_query("harry pottre").execute::<Movie>().await?; // Bug! The programmer forgot that the index is containing books and there will be errors at runtime.

Solution

Index should be generic over its contained Document type. That would force the programmer to specify the type of the documents at the index creation.

let books = client.get_index::<Book>("books").await?;
let results = books.search().with_query("harry pottre").execute().await?;

That makes the bug described above impossible and takes advantage of Rust's type checks and inference.
Note: We could also add an execute_dynamic method allowing the programmer to overwrite the type of the index (for this request only).

Panic on large payloads

On extremely large payloads (~512 MB) the SDK panics when trying to write to the index:
thread 'main' panicked at 'called Result::unwrap()on anErrvalue: Unknown("{\"message\":\"Payload to large\",\"errorCode\":\"payload_too_large\",\"errorType\":\"invalid_request_error\",\"errorLink\":\"https://docs.meilisearch.com/error/payload_too_large\"}")', src/search/indexing/mod.rs:38:5

Upgrade tokio from 0.2 to 0.3

Currently, our tests are failing when trying to upgrade tokio from 0.2 to 0.3. See this failing PR: #55.

The goal of this issue is to upgrade tokio to keep our dependencies up to date.

FIRST ISSUE TO SOLVE: Fix the tests

The tests should work with the latest version of MeiliSearch (currently the v0.12.0)

docker run -it --rm -p 7700:7700 getmeili/meilisearch:v0.12.0 ./meilisearch  --no-analytics=true

Current failure:

failures:

---- src/client.rs - client::Client::get_stats (line 162) stdout ----
Test executable failed (exit code 101).

stderr:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Unknown("invalid type: null, expected a string at line 1 column 39")', src/client.rs:8:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Edit

this failure appears only if the MeiliSearch instance already contains indexes. It should not fail in this context. We should fix this issue. => not true, see this job failure. The bug seems to be random.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.