diff --git a/crates/meilisearch-types/src/settings.rs b/crates/meilisearch-types/src/settings.rs index a5416583b..b90289413 100644 --- a/crates/meilisearch-types/src/settings.rs +++ b/crates/meilisearch-types/src/settings.rs @@ -255,7 +255,7 @@ pub struct Settings { /// Embedder required for performing meaning-based search queries. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] - #[schema(value_type = String)] // TODO: TAMO + #[schema(value_type = Option>)] pub embedders: Setting>, /// Maximum duration of a search query. #[serde(default, skip_serializing_if = "Setting::is_not_set")] diff --git a/crates/meilisearch/src/routes/indexes/documents.rs b/crates/meilisearch/src/routes/indexes/documents.rs index bbe312089..d93f5df9f 100644 --- a/crates/meilisearch/src/routes/indexes/documents.rs +++ b/crates/meilisearch/src/routes/indexes/documents.rs @@ -107,14 +107,18 @@ pub fn configure(cfg: &mut web::ServiceConfig) { ); } -#[derive(Debug, Deserr, IntoParams)] +#[derive(Debug, Deserr, IntoParams, ToSchema)] #[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] +#[into_params(rename_all = "camelCase", parameter_in = Query)] +#[schema(rename_all = "camelCase")] pub struct GetDocument { #[deserr(default, error = DeserrQueryParamError)] #[param(value_type = Option>)] + #[schema(value_type = Option>)] fields: OptionStarOrList, #[deserr(default, error = DeserrQueryParamError)] #[param(value_type = Option)] + #[schema(value_type = Option)] retrieve_vectors: Param, } @@ -195,8 +199,8 @@ impl Aggregate for DocumentsFetchAggregator { /// Get one document from its primary key. #[utoipa::path( get, - path = "/{indexUid}/documents/{documentId}", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents/{documentId}", + tag = "Documents", security(("Bearer" = ["documents.get", "documents.*", "*"])), params( ("indexUid" = String, Path, example = "movies", description = "Index Unique Identifier", nullable = false), @@ -307,12 +311,12 @@ impl Aggregate for DocumentsDeletionAggregator { /// Delete a single document by id. #[utoipa::path( delete, - path = "/{indexUid}/documents/{documentsId}", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents/{documentId}", + tag = "Documents", security(("Bearer" = ["documents.delete", "documents.*", "*"])), params( ("indexUid" = String, Path, example = "movies", description = "Index Unique Identifier", nullable = false), - ("documentsId" = String, Path, example = "movies", description = "Document Identifier", nullable = false), + ("documentId" = String, Path, example = "853", description = "Document Identifier", nullable = false), ), responses( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( @@ -386,6 +390,7 @@ pub struct BrowseQueryGet { #[derive(Debug, Deserr, IntoParams, ToSchema)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[schema(rename_all = "camelCase")] +#[into_params(rename_all = "camelCase", parameter_in = Query)] pub struct BrowseQuery { #[schema(default, example = 150)] #[deserr(default, error = DeserrJsonError)] @@ -409,13 +414,11 @@ pub struct BrowseQuery { /// Get a set of documents. #[utoipa::path( post, - path = "/{indexUid}/documents/fetch", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents/fetch", + tag = "Documents", security(("Bearer" = ["documents.delete", "documents.*", "*"])), - params( - ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), - BrowseQuery, - ), + params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)), + request_body = BrowseQuery, responses( (status = 200, description = "Task successfully enqueued", body = PaginationView, content_type = "application/json", example = json!( { @@ -486,8 +489,8 @@ pub async fn documents_by_query_post( /// Get documents by batches. #[utoipa::path( get, - path = "/{indexUid}/documents", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents", + tag = "Documents", security(("Bearer" = ["documents.get", "documents.*", "*"])), params( ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), @@ -607,7 +610,7 @@ fn documents_by_query( #[derive(Deserialize, Debug, Deserr, IntoParams)] #[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] -#[into_params(rename_all = "camelCase")] +#[into_params(parameter_in = Query, rename_all = "camelCase")] pub struct UpdateDocumentsQuery { /// The primary key of the documents. primaryKey is optional. If you want to set the primary key of your index through this route, /// it only has to be done the first time you add documents to the index. After which it will be ignored if given. @@ -683,14 +686,15 @@ impl Aggregate for DocumentsAggregator { /// > This object accepts keys corresponding to the different embedders defined your index settings. #[utoipa::path( post, - path = "/{indexUid}/documents", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents", + tag = "Documents", security(("Bearer" = ["documents.add", "documents.*", "*"])), params( ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), // Here we can use the post version of the browse query since it contains the exact same parameter UpdateDocumentsQuery, ), + request_body = serde_json::Value, responses( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( { @@ -783,14 +787,15 @@ pub async fn replace_documents( /// > This object accepts keys corresponding to the different embedders defined your index settings. #[utoipa::path( put, - path = "/{indexUid}/documents", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents", + tag = "Documents", security(("Bearer" = ["documents.add", "documents.*", "*"])), params( ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), // Here we can use the post version of the browse query since it contains the exact same parameter UpdateDocumentsQuery, ), + request_body = serde_json::Value, responses( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( { @@ -1045,18 +1050,18 @@ async fn copy_body_to_file( Ok(read_file) } -/// Delete documents +/// Delete documents by batch /// -/// Delete a selection of documents based on array of document id's. +/// Delete a set of documents based on an array of document ids. #[utoipa::path( - delete, - path = "/{indexUid}/documents", - tags = ["Indexes", "Documents"], + post, + path = "{indexUid}/delete-batch", + tag = "Documents", security(("Bearer" = ["documents.delete", "documents.*", "*"])), params( ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), - // TODO: how to task an array of strings in parameter ), + request_body = Vec, responses( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( { @@ -1116,8 +1121,9 @@ pub async fn delete_documents_batch( Ok(HttpResponse::Accepted().json(task)) } -#[derive(Debug, Deserr, IntoParams)] +#[derive(Debug, Deserr, ToSchema)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] +#[schema(rename_all = "camelCase")] pub struct DocumentDeletionByFilter { #[deserr(error = DeserrJsonError, missing_field_error = DeserrJsonError::missing_document_filter)] filter: Value, @@ -1128,15 +1134,13 @@ pub struct DocumentDeletionByFilter { /// Delete a set of documents based on a filter. #[utoipa::path( post, - path = "/{indexUid}/documents/delete", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents/delete", + tag = "Documents", security(("Bearer" = ["documents.delete", "documents.*", "*"])), - params( - ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), - DocumentDeletionByFilter, - ), + params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)), + request_body = DocumentDeletionByFilter, responses( - (status = 202, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( + (status = ACCEPTED, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( { "taskUid": 147, "indexUid": null, @@ -1242,8 +1246,8 @@ impl Aggregate for EditDocumentsByFunctionAggregator { /// Use a [RHAI function](https://rhai.rs/book/engine/hello-world.html) to edit one or more documents directly in Meilisearch. #[utoipa::path( post, - path = "/{indexUid}/documents/edit", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents/edit", + tag = "Documents", security(("Bearer" = ["documents.*", "*"])), params( ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), @@ -1343,13 +1347,10 @@ pub async fn edit_documents_by_function( /// Delete all documents in the specified index. #[utoipa::path( delete, - path = "/{indexUid}/documents", - tags = ["Indexes", "Documents"], + path = "{indexUid}/documents", + tag = "Documents", security(("Bearer" = ["documents.delete", "documents.*", "*"])), - params( - ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), - UpdateDocumentsQuery, - ), + params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)), responses( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( { diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index b97d129db..bf51ed4de 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -6,6 +6,7 @@ use crate::milli::progress::ProgressStepView; use crate::milli::progress::ProgressView; use crate::routes::batches::AllBatches; use crate::routes::features::RuntimeTogglableFeatures; +use crate::routes::indexes::documents::DocumentDeletionByFilter; use crate::routes::indexes::documents::DocumentEditionByFunction; use crate::routes::multi_search::SearchResults; use crate::routes::swap_indexes::SwapIndexesPayload; @@ -86,7 +87,7 @@ pub mod tasks; (name = "Stats", description = "Stats gives extended information and metrics about indexes and the Meilisearch database."), ), modifiers(&OpenApiAuth), - components(schemas(AllBatches, BatchStats, ProgressStepView, ProgressView, BatchView, RuntimeTogglableFeatures, SwapIndexesPayload, DocumentEditionByFunction, MergeFacets, FederationOptions, SearchQueryWithIndex, Federation, FederatedSearch, FederatedSearchResult, SearchResults, SearchResultWithIndex, SimilarQuery, SimilarResult, PaginationView, BrowseQuery, UpdateIndexRequest, IndexUid, IndexCreateRequest, KeyView, Action, CreateApiKey, UpdateStderrLogs, LogMode, GetLogs, IndexStats, Stats, HealthStatus, HealthResponse, VersionResponse, Code, ErrorType, AllTasks, TaskView, Status, DetailsView, ResponseError, Settings, Settings, TypoSettings, MinWordSizeTyposSetting, FacetingSettings, PaginationSettings, SummarizedTaskView, Kind)) + components(schemas(DocumentDeletionByFilter, AllBatches, BatchStats, ProgressStepView, ProgressView, BatchView, RuntimeTogglableFeatures, SwapIndexesPayload, DocumentEditionByFunction, MergeFacets, FederationOptions, SearchQueryWithIndex, Federation, FederatedSearch, FederatedSearchResult, SearchResults, SearchResultWithIndex, SimilarQuery, SimilarResult, PaginationView, BrowseQuery, UpdateIndexRequest, IndexUid, IndexCreateRequest, KeyView, Action, CreateApiKey, UpdateStderrLogs, LogMode, GetLogs, IndexStats, Stats, HealthStatus, HealthResponse, VersionResponse, Code, ErrorType, AllTasks, TaskView, Status, DetailsView, ResponseError, Settings, Settings, TypoSettings, MinWordSizeTyposSetting, FacetingSettings, PaginationSettings, SummarizedTaskView, Kind)) )] pub struct MeilisearchApi;