mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-25 19:45:05 +08:00
Implements the get and delete tasks route
This commit is contained in:
parent
e78da35287
commit
4859a36cb6
39
Cargo.lock
generated
39
Cargo.lock
generated
@ -3455,6 +3455,8 @@ dependencies = [
|
|||||||
"tracing-trace",
|
"tracing-trace",
|
||||||
"url",
|
"url",
|
||||||
"urlencoding",
|
"urlencoding",
|
||||||
|
"utoipa",
|
||||||
|
"utoipa-scalar",
|
||||||
"uuid",
|
"uuid",
|
||||||
"wiremock",
|
"wiremock",
|
||||||
"yaup",
|
"yaup",
|
||||||
@ -3507,6 +3509,7 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"utoipa",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5841,6 +5844,42 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa"
|
||||||
|
version = "5.0.0-alpha.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c082de846a4d434a9dcfe3358dbe4a0aa5d4f826c3af29cdbd97404e1ffe71f4"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"utoipa-gen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa-gen"
|
||||||
|
version = "5.0.0-alpha.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84a71c23e17df16027cc552b5b249a2a5e6a1ea36ab37363a1ac29b69ab36035"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn 2.0.60",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa-scalar"
|
||||||
|
version = "0.2.0-alpha.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c851bc855ea797c92d61de0cd4d36195c01657bc92e42a02fd1373897d6bfe7"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"utoipa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
|
@ -37,6 +37,7 @@ time = { version = "0.3.36", features = [
|
|||||||
"macros",
|
"macros",
|
||||||
] }
|
] }
|
||||||
tokio = "1.38"
|
tokio = "1.38"
|
||||||
|
utoipa = { version = "5.0.0-alpha.1" }
|
||||||
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -16,6 +16,7 @@ use std::ops::Deref;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use deserr::{DeserializeError, Deserr, MergeWithError, ValueKind};
|
use deserr::{DeserializeError, Deserr, MergeWithError, ValueKind};
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use super::{DeserrParseBoolError, DeserrParseIntError};
|
use super::{DeserrParseBoolError, DeserrParseIntError};
|
||||||
use crate::index_uid::IndexUid;
|
use crate::index_uid::IndexUid;
|
||||||
@ -29,6 +30,12 @@ use crate::tasks::{Kind, Status};
|
|||||||
#[derive(Default, Debug, Clone, Copy)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
pub struct Param<T>(pub T);
|
pub struct Param<T>(pub T);
|
||||||
|
|
||||||
|
impl<'a, T: ToSchema<'a>> ToSchema<'a> for Param<T> {
|
||||||
|
fn schema() -> (&'a str, utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>) {
|
||||||
|
T::schema()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for Param<T> {
|
impl<T> Deref for Param<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
|
@ -7,9 +7,11 @@ use aweb::rt::task::JoinError;
|
|||||||
use convert_case::Casing;
|
use convert_case::Casing;
|
||||||
use milli::heed::{Error as HeedError, MdbError};
|
use milli::heed::{Error as HeedError, MdbError};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[schema(rename_all = "camelCase")]
|
||||||
pub struct ResponseError {
|
pub struct ResponseError {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub code: StatusCode,
|
pub code: StatusCode,
|
||||||
|
@ -13,6 +13,7 @@ use milli::proximity::ProximityPrecision;
|
|||||||
use milli::update::Setting;
|
use milli::update::Setting;
|
||||||
use milli::{Criterion, CriterionError, Index, DEFAULT_VALUES_PER_FACET};
|
use milli::{Criterion, CriterionError, Index, DEFAULT_VALUES_PER_FACET};
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::deserr::DeserrJsonError;
|
use crate::deserr::DeserrJsonError;
|
||||||
use crate::error::deserr_codes::*;
|
use crate::error::deserr_codes::*;
|
||||||
@ -69,54 +70,63 @@ fn validate_min_word_size_for_typo_setting<E: DeserializeError>(
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
#[deserr(deny_unknown_fields, rename_all = camelCase, validate = validate_min_word_size_for_typo_setting -> DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
#[deserr(deny_unknown_fields, rename_all = camelCase, validate = validate_min_word_size_for_typo_setting -> DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
||||||
pub struct MinWordSizeTyposSetting {
|
pub struct MinWordSizeTyposSetting {
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<u8>, example = json!(5))]
|
||||||
pub one_typo: Setting<u8>,
|
pub one_typo: Setting<u8>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<u8>, example = json!(9))]
|
||||||
pub two_typos: Setting<u8>,
|
pub two_typos: Setting<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
#[deserr(deny_unknown_fields, rename_all = camelCase, where_predicate = __Deserr_E: deserr::MergeWithError<DeserrJsonError<InvalidSettingsTypoTolerance>>)]
|
#[deserr(deny_unknown_fields, rename_all = camelCase, where_predicate = __Deserr_E: deserr::MergeWithError<DeserrJsonError<InvalidSettingsTypoTolerance>>)]
|
||||||
pub struct TypoSettings {
|
pub struct TypoSettings {
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<bool>, example = json!(true))]
|
||||||
pub enabled: Setting<bool>,
|
pub enabled: Setting<bool>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
||||||
|
#[schema(value_type = Option<MinWordSizeTyposSetting>, example = json!({ "oneTypo": 5, "twoTypo": 9 }))]
|
||||||
pub min_word_size_for_typos: Setting<MinWordSizeTyposSetting>,
|
pub min_word_size_for_typos: Setting<MinWordSizeTyposSetting>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<BTreeSet<String>>, example = json!(["iPhone", "phone"]))]
|
||||||
pub disable_on_words: Setting<BTreeSet<String>>,
|
pub disable_on_words: Setting<BTreeSet<String>>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<BTreeSet<String>>, example = json!(["uuid", "url"]))]
|
||||||
pub disable_on_attributes: Setting<BTreeSet<String>>,
|
pub disable_on_attributes: Setting<BTreeSet<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
#[deserr(rename_all = camelCase, deny_unknown_fields)]
|
#[deserr(rename_all = camelCase, deny_unknown_fields)]
|
||||||
pub struct FacetingSettings {
|
pub struct FacetingSettings {
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<usize>, example = json!(10))]
|
||||||
pub max_values_per_facet: Setting<usize>,
|
pub max_values_per_facet: Setting<usize>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<BTreeMap<String, FacetValuesSort>>, example = json!({ "genre": FacetValuesSort::Count }))]
|
||||||
pub sort_facet_values_by: Setting<BTreeMap<String, FacetValuesSort>>,
|
pub sort_facet_values_by: Setting<BTreeMap<String, FacetValuesSort>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
#[deserr(rename_all = camelCase, deny_unknown_fields)]
|
#[deserr(rename_all = camelCase, deny_unknown_fields)]
|
||||||
pub struct PaginationSettings {
|
pub struct PaginationSettings {
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default)]
|
#[deserr(default)]
|
||||||
|
#[schema(value_type = Option<usize>, example = json!(250))]
|
||||||
pub max_total_hits: Setting<usize>,
|
pub max_total_hits: Setting<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,67 +147,100 @@ impl MergeWithError<milli::CriterionError> for DeserrJsonError<InvalidSettingsRa
|
|||||||
/// Holds all the settings for an index. `T` can either be `Checked` if they represents settings
|
/// Holds all the settings for an index. `T` can either be `Checked` if they represents settings
|
||||||
/// whose validity is guaranteed, or `Unchecked` if they need to be validated. In the later case, a
|
/// whose validity is guaranteed, or `Unchecked` if they need to be validated. In the later case, a
|
||||||
/// call to `check` will return a `Settings<Checked>` from a `Settings<Unchecked>`.
|
/// call to `check` will return a `Settings<Checked>` from a `Settings<Unchecked>`.
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)]
|
||||||
#[serde(
|
#[serde(
|
||||||
deny_unknown_fields,
|
deny_unknown_fields,
|
||||||
rename_all = "camelCase",
|
rename_all = "camelCase",
|
||||||
bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'static>")
|
bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'static>")
|
||||||
)]
|
)]
|
||||||
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)]
|
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)]
|
||||||
|
#[schema(rename_all = "camelCase")]
|
||||||
pub struct Settings<T> {
|
pub struct Settings<T> {
|
||||||
|
/// Fields displayed in the returned documents.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsDisplayedAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsDisplayedAttributes>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["id", "title", "description", "url"]))]
|
||||||
pub displayed_attributes: WildcardSetting,
|
pub displayed_attributes: WildcardSetting,
|
||||||
|
/// Fields in which to search for matching query words sorted by order of importance.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSearchableAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSearchableAttributes>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["title", "description"]))]
|
||||||
pub searchable_attributes: WildcardSetting,
|
pub searchable_attributes: WildcardSetting,
|
||||||
|
/// Attributes to use for faceting and filtering. See [Filtering and Faceted Search](https://www.meilisearch.com/docs/learn/filtering_and_sorting/search_with_facet_filters).
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsFilterableAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsFilterableAttributes>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["release_date", "genre"]))]
|
||||||
pub filterable_attributes: Setting<BTreeSet<String>>,
|
pub filterable_attributes: Setting<BTreeSet<String>>,
|
||||||
|
/// Attributes to use when sorting search results.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSortableAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSortableAttributes>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["release_date"]))]
|
||||||
pub sortable_attributes: Setting<BTreeSet<String>>,
|
pub sortable_attributes: Setting<BTreeSet<String>>,
|
||||||
|
/// List of ranking rules sorted by order of importance. The order is customizable.
|
||||||
|
/// [A list of ordered built-in ranking rules](https://www.meilisearch.com/docs/learn/relevancy/relevancy).
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsRankingRules>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsRankingRules>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!([RankingRuleView::Words, RankingRuleView::Typo, RankingRuleView::Proximity, RankingRuleView::Attribute, RankingRuleView::Exactness]))]
|
||||||
pub ranking_rules: Setting<Vec<RankingRuleView>>,
|
pub ranking_rules: Setting<Vec<RankingRuleView>>,
|
||||||
|
/// List of words ignored when present in search queries.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsStopWords>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsStopWords>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["the", "a", "them", "their"]))]
|
||||||
pub stop_words: Setting<BTreeSet<String>>,
|
pub stop_words: Setting<BTreeSet<String>>,
|
||||||
|
/// List of characters not delimiting where one term begins and ends.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsNonSeparatorTokens>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsNonSeparatorTokens>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!([" ", "\n"]))]
|
||||||
pub non_separator_tokens: Setting<BTreeSet<String>>,
|
pub non_separator_tokens: Setting<BTreeSet<String>>,
|
||||||
|
/// List of characters delimiting where one term begins and ends.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSeparatorTokens>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSeparatorTokens>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["S"]))]
|
||||||
pub separator_tokens: Setting<BTreeSet<String>>,
|
pub separator_tokens: Setting<BTreeSet<String>>,
|
||||||
|
/// List of strings Meilisearch should parse as a single term.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsDictionary>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsDictionary>)]
|
||||||
|
#[schema(value_type = Option<Vec<String>>, example = json!(["iPhone pro"]))]
|
||||||
pub dictionary: Setting<BTreeSet<String>>,
|
pub dictionary: Setting<BTreeSet<String>>,
|
||||||
|
/// List of associated words treated similarly. A word associated to an array of word as synonyms.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSynonyms>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSynonyms>)]
|
||||||
|
#[schema(value_type = Option<BTreeMap<String, Vec<String>>>, example = json!({ "he": ["she", "they", "them"], "phone": ["iPhone", "android"]}))]
|
||||||
pub synonyms: Setting<BTreeMap<String, Vec<String>>>,
|
pub synonyms: Setting<BTreeMap<String, Vec<String>>>,
|
||||||
|
/// Search returns documents with distinct (different) values of the given field.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsDistinctAttribute>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsDistinctAttribute>)]
|
||||||
|
#[schema(value_type = Option<String>, example = json!("sku"))]
|
||||||
pub distinct_attribute: Setting<String>,
|
pub distinct_attribute: Setting<String>,
|
||||||
|
/// Precision level when calculating the proximity ranking rule.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsProximityPrecision>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsProximityPrecision>)]
|
||||||
|
#[schema(value_type = Option<String>, example = json!(ProximityPrecisionView::ByAttribute))]
|
||||||
pub proximity_precision: Setting<ProximityPrecisionView>,
|
pub proximity_precision: Setting<ProximityPrecisionView>,
|
||||||
|
/// Customize typo tolerance feature.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsTypoTolerance>)]
|
||||||
|
#[schema(value_type = Option<TypoSettings>, example = json!({ "enabled": true, "disableOnAttributes": ["title"]}))]
|
||||||
pub typo_tolerance: Setting<TypoSettings>,
|
pub typo_tolerance: Setting<TypoSettings>,
|
||||||
|
/// Faceting settings.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsFaceting>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsFaceting>)]
|
||||||
|
#[schema(value_type = Option<FacetingSettings>, example = json!({ "maxValuesPerFacet": 10, "sortFacetValuesBy": { "genre": FacetValuesSort::Count }}))]
|
||||||
pub faceting: Setting<FacetingSettings>,
|
pub faceting: Setting<FacetingSettings>,
|
||||||
|
/// Pagination settings.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsPagination>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsPagination>)]
|
||||||
|
#[schema(value_type = Option<PaginationSettings>, example = json!({ "maxValuesPerFacet": 10, "sortFacetValuesBy": { "genre": FacetValuesSort::Count }}))]
|
||||||
pub pagination: Setting<PaginationSettings>,
|
pub pagination: Setting<PaginationSettings>,
|
||||||
|
|
||||||
|
/// Embedder required for performing meaning-based search queries.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsEmbedders>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsEmbedders>)]
|
||||||
pub embedders: Setting<BTreeMap<String, Setting<milli::vector::settings::EmbeddingSettings>>>,
|
pub embedders: Setting<BTreeMap<String, Setting<milli::vector::settings::EmbeddingSettings>>>,
|
||||||
|
/// Maximum duration of a search query.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSearchCutoffMs>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSearchCutoffMs>)]
|
||||||
|
#[schema(value_type = Option<u64>, example = json!(50))]
|
||||||
pub search_cutoff_ms: Setting<u64>,
|
pub search_cutoff_ms: Setting<u64>,
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsLocalizedAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsLocalizedAttributes>)]
|
||||||
@ -865,7 +908,7 @@ impl From<ProximityPrecisionView> for ProximityPrecision {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, ToSchema)]
|
||||||
pub struct WildcardSetting(Setting<Vec<String>>);
|
pub struct WildcardSetting(Setting<Vec<String>>);
|
||||||
|
|
||||||
impl From<Setting<Vec<String>>> for WildcardSetting {
|
impl From<Setting<Vec<String>>> for WildcardSetting {
|
||||||
|
@ -1,30 +1,47 @@
|
|||||||
use milli::Object;
|
use milli::Object;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::error::ResponseError;
|
use crate::error::ResponseError;
|
||||||
use crate::settings::{Settings, Unchecked};
|
use crate::settings::{Settings, Unchecked};
|
||||||
use crate::tasks::{serialize_duration, Details, IndexSwap, Kind, Status, Task, TaskId};
|
use crate::tasks::{serialize_duration, Details, IndexSwap, Kind, Status, Task, TaskId};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[schema(rename_all = "camelCase")]
|
||||||
pub struct TaskView {
|
pub struct TaskView {
|
||||||
|
/// The unique sequential identifier of the task.
|
||||||
|
#[schema(value_type = u32, example = 4312)]
|
||||||
pub uid: TaskId,
|
pub uid: TaskId,
|
||||||
|
/// The unique identifier of the index where this task is operated.
|
||||||
|
#[schema(example = json!("movies"))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub index_uid: Option<String>,
|
pub index_uid: Option<String>,
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
|
/// The type of the task.
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub kind: Kind,
|
pub kind: Kind,
|
||||||
|
/// The uid of the task that performed the taskCancelation if the task has been canceled.
|
||||||
|
#[schema(value_type = Option<u32>, example = json!(4326))]
|
||||||
pub canceled_by: Option<TaskId>,
|
pub canceled_by: Option<TaskId>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub details: Option<DetailsView>,
|
pub details: Option<DetailsView>,
|
||||||
pub error: Option<ResponseError>,
|
pub error: Option<ResponseError>,
|
||||||
|
/// Total elasped time the engine was in processing state expressed as a `ISO-8601` duration format.
|
||||||
|
#[schema(value_type = Option<String>, example = json!(null))]
|
||||||
#[serde(serialize_with = "serialize_duration", default)]
|
#[serde(serialize_with = "serialize_duration", default)]
|
||||||
pub duration: Option<Duration>,
|
pub duration: Option<Duration>,
|
||||||
|
/// An `RFC 3339` format for date/time/duration.
|
||||||
|
#[schema(value_type = String, example = json!("2024-08-08_14:12:09.393Z"))]
|
||||||
#[serde(with = "time::serde::rfc3339")]
|
#[serde(with = "time::serde::rfc3339")]
|
||||||
pub enqueued_at: OffsetDateTime,
|
pub enqueued_at: OffsetDateTime,
|
||||||
|
/// An `RFC 3339` format for date/time/duration.
|
||||||
|
#[schema(value_type = String, example = json!("2024-08-08_14:12:09.393Z"))]
|
||||||
#[serde(with = "time::serde::rfc3339::option", default)]
|
#[serde(with = "time::serde::rfc3339::option", default)]
|
||||||
pub started_at: Option<OffsetDateTime>,
|
pub started_at: Option<OffsetDateTime>,
|
||||||
|
/// An `RFC 3339` format for date/time/duration.
|
||||||
|
#[schema(value_type = String, example = json!("2024-08-08_14:12:09.393Z"))]
|
||||||
#[serde(with = "time::serde::rfc3339::option", default)]
|
#[serde(with = "time::serde::rfc3339::option", default)]
|
||||||
pub finished_at: Option<OffsetDateTime>,
|
pub finished_at: Option<OffsetDateTime>,
|
||||||
}
|
}
|
||||||
@ -47,37 +64,52 @@ impl TaskView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Eq, Clone, Serialize)]
|
/// Details information of the task payload.
|
||||||
|
#[derive(Default, Debug, PartialEq, Eq, Clone, Serialize, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[schema(rename_all = "camelCase")]
|
||||||
pub struct DetailsView {
|
pub struct DetailsView {
|
||||||
|
/// Number of documents received for documentAdditionOrUpdate task.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub received_documents: Option<u64>,
|
pub received_documents: Option<u64>,
|
||||||
|
/// Number of documents finally indexed for documentAdditionOrUpdate task or a documentAdditionOrUpdate batch of tasks.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub indexed_documents: Option<Option<u64>>,
|
pub indexed_documents: Option<Option<u64>>,
|
||||||
|
/// Number of documents edited for editDocumentByFunction task.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub edited_documents: Option<Option<u64>>,
|
pub edited_documents: Option<Option<u64>>,
|
||||||
|
/// Value for the primaryKey field encountered if any for indexCreation or indexUpdate task.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub primary_key: Option<Option<String>>,
|
pub primary_key: Option<Option<String>>,
|
||||||
|
/// Number of provided document ids for the documentDeletion task.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub provided_ids: Option<usize>,
|
pub provided_ids: Option<usize>,
|
||||||
|
/// Number of documents finally deleted for documentDeletion and indexDeletion tasks.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub deleted_documents: Option<Option<u64>>,
|
pub deleted_documents: Option<Option<u64>>,
|
||||||
|
/// Number of tasks that match the request for taskCancelation or taskDeletion tasks.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub matched_tasks: Option<u64>,
|
pub matched_tasks: Option<u64>,
|
||||||
|
/// Number of tasks canceled for taskCancelation.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub canceled_tasks: Option<Option<u64>>,
|
pub canceled_tasks: Option<Option<u64>>,
|
||||||
|
/// Number of tasks deleted for taskDeletion.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub deleted_tasks: Option<Option<u64>>,
|
pub deleted_tasks: Option<Option<u64>>,
|
||||||
|
/// Original filter query for taskCancelation or taskDeletion tasks.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub original_filter: Option<Option<String>>,
|
pub original_filter: Option<Option<String>>,
|
||||||
|
/// Identifier generated for the dump for dumpCreation task.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub dump_uid: Option<Option<String>>,
|
pub dump_uid: Option<Option<String>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub context: Option<Option<Object>>,
|
pub context: Option<Option<Object>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub function: Option<String>,
|
pub function: Option<String>,
|
||||||
|
/// [Learn more about the settings in this guide](https://www.meilisearch.com/docs/reference/api/settings).
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(flatten)]
|
// #[serde(flatten)]
|
||||||
|
#[schema(value_type = Option<Settings<Unchecked>>)]
|
||||||
pub settings: Option<Box<Settings<Unchecked>>>,
|
pub settings: Option<Box<Settings<Unchecked>>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub swaps: Option<Vec<IndexSwap>>,
|
pub swaps: Option<Vec<IndexSwap>>,
|
||||||
|
@ -9,6 +9,7 @@ use milli::Object;
|
|||||||
use roaring::RoaringBitmap;
|
use roaring::RoaringBitmap;
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
|
use utoipa::{IntoParams, ToSchema};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::error::ResponseError;
|
use crate::error::ResponseError;
|
||||||
@ -361,7 +362,9 @@ impl From<&KindWithContent> for Option<Details> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence)]
|
/// The status of a task.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence, ToSchema)]
|
||||||
|
#[schema(example = json!(Status::Processing))]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Enqueued,
|
Enqueued,
|
||||||
@ -420,8 +423,10 @@ impl fmt::Display for ParseTaskStatusError {
|
|||||||
}
|
}
|
||||||
impl std::error::Error for ParseTaskStatusError {}
|
impl std::error::Error for ParseTaskStatusError {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence)]
|
/// The type of the task.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[schema(rename_all = "camelCase", example = json!(Kind::DocumentAdditionOrUpdate))]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
DocumentAdditionOrUpdate,
|
DocumentAdditionOrUpdate,
|
||||||
DocumentEdition,
|
DocumentEdition,
|
||||||
|
@ -104,6 +104,8 @@ tracing-trace = { version = "0.1.0", path = "../tracing-trace" }
|
|||||||
tracing-actix-web = "0.7.11"
|
tracing-actix-web = "0.7.11"
|
||||||
build-info = { version = "1.7.0", path = "../build-info" }
|
build-info = { version = "1.7.0", path = "../build-info" }
|
||||||
roaring = "0.10.2"
|
roaring = "0.10.2"
|
||||||
|
utoipa = { version = "5.0.0-alpha.1", features = ["actix_extras", "non_strict_integers"] }
|
||||||
|
utoipa-scalar = { version = "0.2.0-alpha.0", features = ["actix-web"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.10.0"
|
actix-rt = "2.10.0"
|
||||||
|
@ -24,6 +24,7 @@ use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
|||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::layer::SubscriberExt as _;
|
use tracing_subscriber::layer::SubscriberExt as _;
|
||||||
use tracing_subscriber::Layer;
|
use tracing_subscriber::Layer;
|
||||||
|
use utoipa::OpenApi;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: MiMalloc = MiMalloc;
|
static ALLOC: MiMalloc = MiMalloc;
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use crate::extractors::authentication::policies::*;
|
||||||
|
use crate::extractors::authentication::GuardedData;
|
||||||
|
use crate::search_queue::SearchQueue;
|
||||||
|
use crate::Opt;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use index_scheduler::IndexScheduler;
|
use index_scheduler::IndexScheduler;
|
||||||
use meilisearch_auth::AuthController;
|
use meilisearch_auth::AuthController;
|
||||||
|
use meilisearch_types::deserr::query_params::Param;
|
||||||
use meilisearch_types::error::{Code, ResponseError};
|
use meilisearch_types::error::{Code, ResponseError};
|
||||||
use meilisearch_types::settings::{Settings, Unchecked};
|
use meilisearch_types::settings::{Settings, Unchecked};
|
||||||
use meilisearch_types::tasks::{Kind, Status, Task, TaskId};
|
use meilisearch_types::tasks::{Kind, Status, Task, TaskId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
use utoipa::OpenApi;
|
||||||
use crate::extractors::authentication::policies::*;
|
use utoipa_scalar::{Scalar, Servable as ScalarServable};
|
||||||
use crate::extractors::authentication::GuardedData;
|
|
||||||
use crate::search_queue::SearchQueue;
|
|
||||||
use crate::Opt;
|
|
||||||
|
|
||||||
const PAGINATION_DEFAULT_LIMIT: usize = 20;
|
const PAGINATION_DEFAULT_LIMIT: usize = 20;
|
||||||
|
|
||||||
@ -29,8 +31,19 @@ mod snapshot;
|
|||||||
mod swap_indexes;
|
mod swap_indexes;
|
||||||
pub mod tasks;
|
pub mod tasks;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
nest((path = "/tasks", api = tasks::TaskApi) ),
|
||||||
|
// paths(get_todos, create_todo, delete_todo, get_todo_by_id, update_todo, search_todos),
|
||||||
|
// components(schemas(TaskId))
|
||||||
|
)]
|
||||||
|
pub struct MeilisearchApi;
|
||||||
|
|
||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
|
let openapi = MeilisearchApi::openapi();
|
||||||
|
|
||||||
cfg.service(web::scope("/tasks").configure(tasks::configure))
|
cfg.service(web::scope("/tasks").configure(tasks::configure))
|
||||||
|
.service(Scalar::with_url("/scalar", openapi.clone()))
|
||||||
.service(web::resource("/health").route(web::get().to(get_health)))
|
.service(web::resource("/health").route(web::get().to(get_health)))
|
||||||
.service(web::scope("/logs").configure(logs::configure))
|
.service(web::scope("/logs").configure(logs::configure))
|
||||||
.service(web::scope("/keys").configure(api_key::configure))
|
.service(web::scope("/keys").configure(api_key::configure))
|
||||||
|
@ -8,8 +8,12 @@ use meilisearch_types::deserr::DeserrQueryParamError;
|
|||||||
use meilisearch_types::error::deserr_codes::*;
|
use meilisearch_types::error::deserr_codes::*;
|
||||||
use meilisearch_types::error::{InvalidTaskDateError, ResponseError};
|
use meilisearch_types::error::{InvalidTaskDateError, ResponseError};
|
||||||
use meilisearch_types::index_uid::IndexUid;
|
use meilisearch_types::index_uid::IndexUid;
|
||||||
|
use meilisearch_types::settings::{
|
||||||
|
Checked, FacetingSettings, MinWordSizeTyposSetting, PaginationSettings, Settings, TypoSettings,
|
||||||
|
Unchecked,
|
||||||
|
};
|
||||||
use meilisearch_types::star_or::{OptionStarOr, OptionStarOrList};
|
use meilisearch_types::star_or::{OptionStarOr, OptionStarOrList};
|
||||||
use meilisearch_types::task_view::TaskView;
|
use meilisearch_types::task_view::{DetailsView, TaskView};
|
||||||
use meilisearch_types::tasks::{Kind, KindWithContent, Status};
|
use meilisearch_types::tasks::{Kind, KindWithContent, Status};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
@ -17,6 +21,7 @@ use time::format_description::well_known::Rfc3339;
|
|||||||
use time::macros::format_description;
|
use time::macros::format_description;
|
||||||
use time::{Date, Duration, OffsetDateTime, Time};
|
use time::{Date, Duration, OffsetDateTime, Time};
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
use utoipa::{IntoParams, OpenApi, ToSchema};
|
||||||
|
|
||||||
use super::{get_task_id, is_dry_run, SummarizedTaskView};
|
use super::{get_task_id, is_dry_run, SummarizedTaskView};
|
||||||
use crate::analytics::Analytics;
|
use crate::analytics::Analytics;
|
||||||
@ -27,6 +32,16 @@ use crate::Opt;
|
|||||||
|
|
||||||
const DEFAULT_LIMIT: u32 = 20;
|
const DEFAULT_LIMIT: u32 = 20;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
paths(get_tasks, delete_tasks),
|
||||||
|
info(
|
||||||
|
title = "The tasks route gives information about the progress of the [asynchronous operations](https://docs.meilisearch.com/learn/advanced/asynchronous_operations.html)."
|
||||||
|
),
|
||||||
|
components(schemas(AllTasks, TaskView, Status, DetailsView, ResponseError, Settings<Unchecked>, Settings<Checked>, TypoSettings, MinWordSizeTyposSetting, FacetingSettings, PaginationSettings))
|
||||||
|
)]
|
||||||
|
pub struct TaskApi;
|
||||||
|
|
||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
web::resource("")
|
web::resource("")
|
||||||
@ -36,36 +51,54 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
.service(web::resource("/cancel").route(web::post().to(SeqHandler(cancel_tasks))))
|
.service(web::resource("/cancel").route(web::post().to(SeqHandler(cancel_tasks))))
|
||||||
.service(web::resource("/{task_id}").route(web::get().to(SeqHandler(get_task))));
|
.service(web::resource("/{task_id}").route(web::get().to(SeqHandler(get_task))));
|
||||||
}
|
}
|
||||||
#[derive(Debug, Deserr)]
|
|
||||||
|
#[derive(Debug, Deserr, IntoParams)]
|
||||||
#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)]
|
#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)]
|
||||||
|
#[into_params(rename_all = "camelCase", parameter_in = Query)]
|
||||||
pub struct TasksFilterQuery {
|
pub struct TasksFilterQuery {
|
||||||
|
/// Maximum number of results to return.
|
||||||
#[deserr(default = Param(DEFAULT_LIMIT), error = DeserrQueryParamError<InvalidTaskLimit>)]
|
#[deserr(default = Param(DEFAULT_LIMIT), error = DeserrQueryParamError<InvalidTaskLimit>)]
|
||||||
|
#[param(required = false, value_type = u32, example = 12, default = json!(DEFAULT_LIMIT))]
|
||||||
pub limit: Param<u32>,
|
pub limit: Param<u32>,
|
||||||
|
/// Fetch the next set of results from the given uid.
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskFrom>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskFrom>)]
|
||||||
|
#[param(required = false, value_type = Option<u32>, example = 12421)]
|
||||||
pub from: Option<Param<TaskId>>,
|
pub from: Option<Param<TaskId>>,
|
||||||
|
|
||||||
|
/// Permits to filter tasks by their uid. By default, when the uids query parameter is not set, all task uids are returned. It's possible to specify several uids by separating them with the `,` character.
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskUids>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskUids>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<u32>>, example = json!([231, 423, 598]))]
|
||||||
pub uids: OptionStarOrList<u32>,
|
pub uids: OptionStarOrList<u32>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskCanceledBy>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskCanceledBy>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<u32>>, example = json!([374]))]
|
||||||
pub canceled_by: OptionStarOrList<u32>,
|
pub canceled_by: OptionStarOrList<u32>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskTypes>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskTypes>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<Kind>>, example = json!([Kind::DocumentDeletion]))]
|
||||||
pub types: OptionStarOrList<Kind>,
|
pub types: OptionStarOrList<Kind>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskStatuses>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskStatuses>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<Status>>, example = json!([Status::Succeeded, Status::Failed, Status::Canceled]))]
|
||||||
pub statuses: OptionStarOrList<Status>,
|
pub statuses: OptionStarOrList<Status>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidIndexUid>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidIndexUid>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<String>>, example = json!(["movies", "theater"]))]
|
||||||
pub index_uids: OptionStarOrList<IndexUid>,
|
pub index_uids: OptionStarOrList<IndexUid>,
|
||||||
|
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_enqueued_at: OptionStarOr<OffsetDateTime>,
|
pub after_enqueued_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_enqueued_at: OptionStarOr<OffsetDateTime>,
|
pub before_enqueued_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_started_at: OptionStarOr<OffsetDateTime>,
|
pub after_started_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_started_at: OptionStarOr<OffsetDateTime>,
|
pub before_started_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_finished_at: OptionStarOr<OffsetDateTime>,
|
pub after_finished_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_finished_at: OptionStarOr<OffsetDateTime>,
|
pub before_finished_at: OptionStarOr<OffsetDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,31 +143,43 @@ impl TaskDeletionOrCancelationQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserr)]
|
#[derive(Debug, Deserr, IntoParams)]
|
||||||
#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)]
|
#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)]
|
||||||
|
#[into_params(rename_all = "camelCase", parameter_in = Query)]
|
||||||
pub struct TaskDeletionOrCancelationQuery {
|
pub struct TaskDeletionOrCancelationQuery {
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskUids>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskUids>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<u32>>, example = json!([231, 423, 598]))]
|
||||||
pub uids: OptionStarOrList<u32>,
|
pub uids: OptionStarOrList<u32>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskCanceledBy>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskCanceledBy>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<u32>>, example = json!([374]))]
|
||||||
pub canceled_by: OptionStarOrList<u32>,
|
pub canceled_by: OptionStarOrList<u32>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskTypes>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskTypes>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<Kind>>, example = json!([Kind::DocumentDeletion]))]
|
||||||
pub types: OptionStarOrList<Kind>,
|
pub types: OptionStarOrList<Kind>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskStatuses>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskStatuses>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<Status>>, example = json!([Status::Succeeded, Status::Failed, Status::Canceled]))]
|
||||||
pub statuses: OptionStarOrList<Status>,
|
pub statuses: OptionStarOrList<Status>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidIndexUid>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidIndexUid>)]
|
||||||
|
#[param(required = false, value_type = Option<Vec<String>>, example = json!(["movies", "theater"]))]
|
||||||
pub index_uids: OptionStarOrList<IndexUid>,
|
pub index_uids: OptionStarOrList<IndexUid>,
|
||||||
|
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_enqueued_at: OptionStarOr<OffsetDateTime>,
|
pub after_enqueued_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeEnqueuedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_enqueued_at: OptionStarOr<OffsetDateTime>,
|
pub before_enqueued_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_started_at: OptionStarOr<OffsetDateTime>,
|
pub after_started_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeStartedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_started_at: OptionStarOr<OffsetDateTime>,
|
pub before_started_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskAfterFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_after -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub after_finished_at: OptionStarOr<OffsetDateTime>,
|
pub after_finished_at: OptionStarOr<OffsetDateTime>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidTaskBeforeFinishedAt>, try_from(OptionStarOr<String>) = deserialize_date_before -> InvalidTaskDateError)]
|
||||||
|
#[param(required = false, value_type = Option<String>, example = json!("2024-08-08_16:37:09.971Z"))]
|
||||||
pub before_finished_at: OptionStarOr<OffsetDateTime>,
|
pub before_finished_at: OptionStarOr<OffsetDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +254,23 @@ async fn cancel_tasks(
|
|||||||
Ok(HttpResponse::Ok().json(task))
|
Ok(HttpResponse::Ok().json(task))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Delete tasks.
|
||||||
|
///
|
||||||
|
/// Delete [tasks](https://docs.meilisearch.com/learn/advanced/asynchronous_operations.html) on filter
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "",
|
||||||
|
params(TaskDeletionOrCancelationQuery),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!({
|
||||||
|
"taskUid": 147,
|
||||||
|
"indexUid": null,
|
||||||
|
"status": "enqueued",
|
||||||
|
"type": "taskDeletion",
|
||||||
|
"enqueuedAt": "2024-08-08T17:05:55.791772Z"
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
)]
|
||||||
async fn delete_tasks(
|
async fn delete_tasks(
|
||||||
index_scheduler: GuardedData<ActionPolicy<{ actions::TASKS_DELETE }>, Data<IndexScheduler>>,
|
index_scheduler: GuardedData<ActionPolicy<{ actions::TASKS_DELETE }>, Data<IndexScheduler>>,
|
||||||
params: AwebQueryParameter<TaskDeletionOrCancelationQuery, DeserrQueryParamError>,
|
params: AwebQueryParameter<TaskDeletionOrCancelationQuery, DeserrQueryParamError>,
|
||||||
@ -258,15 +320,56 @@ async fn delete_tasks(
|
|||||||
Ok(HttpResponse::Ok().json(task))
|
Ok(HttpResponse::Ok().json(task))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct AllTasks {
|
pub struct AllTasks {
|
||||||
results: Vec<TaskView>,
|
results: Vec<TaskView>,
|
||||||
|
/// Total number of browsable results using offset/limit parameters for the given resource.
|
||||||
total: u64,
|
total: u64,
|
||||||
|
/// Limit given for the query. If limit is not provided as a query parameter, this parameter displays the default limit value.
|
||||||
limit: u32,
|
limit: u32,
|
||||||
|
/// The first task uid returned.
|
||||||
from: Option<u32>,
|
from: Option<u32>,
|
||||||
|
/// Represents the value to send in from to fetch the next slice of the results. The first item for the next slice starts at this exact number. When the returned value is null, it means that all the data have been browsed in the given order.
|
||||||
next: Option<u32>,
|
next: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all tasks
|
||||||
|
///
|
||||||
|
/// Get all [tasks](https://docs.meilisearch.com/learn/advanced/asynchronous_operations.html)
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "",
|
||||||
|
params(TasksFilterQuery),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Get all tasks", body = AllTasks, content_type = "application/json", example = json!({
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"uid": 144,
|
||||||
|
"indexUid": "mieli",
|
||||||
|
"status": "succeeded",
|
||||||
|
"type": "settingsUpdate",
|
||||||
|
"canceledBy": null,
|
||||||
|
"details": {
|
||||||
|
"settings": {
|
||||||
|
"filterableAttributes": [
|
||||||
|
"play_count"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": null,
|
||||||
|
"duration": "PT0.009330S",
|
||||||
|
"enqueuedAt": "2024-08-08T09:01:13.348471Z",
|
||||||
|
"startedAt": "2024-08-08T09:01:13.349442Z",
|
||||||
|
"finishedAt": "2024-08-08T09:01:13.358772Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1,
|
||||||
|
"limit": 1,
|
||||||
|
"from": 144,
|
||||||
|
"next": null
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
)]
|
||||||
async fn get_tasks(
|
async fn get_tasks(
|
||||||
index_scheduler: GuardedData<ActionPolicy<{ actions::TASKS_GET }>, Data<IndexScheduler>>,
|
index_scheduler: GuardedData<ActionPolicy<{ actions::TASKS_GET }>, Data<IndexScheduler>>,
|
||||||
params: AwebQueryParameter<TasksFilterQuery, DeserrQueryParamError>,
|
params: AwebQueryParameter<TasksFilterQuery, DeserrQueryParamError>,
|
||||||
|
Loading…
Reference in New Issue
Block a user