fix and review all the documents route

This commit is contained in:
Tamo 2024-12-26 18:26:30 +01:00
parent 1dd33af8a3
commit aab6ffec30
No known key found for this signature in database
GPG Key ID: 20CD8020AFA88D69
3 changed files with 45 additions and 43 deletions

View File

@ -255,7 +255,7 @@ pub struct Settings<T> {
/// Embedder required for performing meaning-based search queries. /// 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>)]
#[schema(value_type = String)] // TODO: TAMO #[schema(value_type = Option<BTreeMap<String, SettingEmbeddingSettings>>)]
pub embedders: Setting<BTreeMap<String, SettingEmbeddingSettings>>, pub embedders: Setting<BTreeMap<String, SettingEmbeddingSettings>>,
/// Maximum duration of a search query. /// Maximum duration of a search query.
#[serde(default, skip_serializing_if = "Setting::is_not_set")] #[serde(default, skip_serializing_if = "Setting::is_not_set")]

View File

@ -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)] #[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)]
#[into_params(rename_all = "camelCase", parameter_in = Query)]
#[schema(rename_all = "camelCase")]
pub struct GetDocument { pub struct GetDocument {
#[deserr(default, error = DeserrQueryParamError<InvalidDocumentFields>)] #[deserr(default, error = DeserrQueryParamError<InvalidDocumentFields>)]
#[param(value_type = Option<Vec<String>>)] #[param(value_type = Option<Vec<String>>)]
#[schema(value_type = Option<Vec<String>>)]
fields: OptionStarOrList<String>, fields: OptionStarOrList<String>,
#[deserr(default, error = DeserrQueryParamError<InvalidDocumentRetrieveVectors>)] #[deserr(default, error = DeserrQueryParamError<InvalidDocumentRetrieveVectors>)]
#[param(value_type = Option<bool>)] #[param(value_type = Option<bool>)]
#[schema(value_type = Option<bool>)]
retrieve_vectors: Param<bool>, retrieve_vectors: Param<bool>,
} }
@ -195,8 +199,8 @@ impl<Method: AggregateMethod> Aggregate for DocumentsFetchAggregator<Method> {
/// Get one document from its primary key. /// Get one document from its primary key.
#[utoipa::path( #[utoipa::path(
get, get,
path = "/{indexUid}/documents/{documentId}", path = "{indexUid}/documents/{documentId}",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.get", "documents.*", "*"])), security(("Bearer" = ["documents.get", "documents.*", "*"])),
params( params(
("indexUid" = String, Path, example = "movies", description = "Index Unique Identifier", nullable = false), ("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. /// Delete a single document by id.
#[utoipa::path( #[utoipa::path(
delete, delete,
path = "/{indexUid}/documents/{documentsId}", path = "{indexUid}/documents/{documentId}",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.delete", "documents.*", "*"])), security(("Bearer" = ["documents.delete", "documents.*", "*"])),
params( params(
("indexUid" = String, Path, example = "movies", description = "Index Unique Identifier", nullable = false), ("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( responses(
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( (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)] #[derive(Debug, Deserr, IntoParams, ToSchema)]
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)]
#[schema(rename_all = "camelCase")] #[schema(rename_all = "camelCase")]
#[into_params(rename_all = "camelCase", parameter_in = Query)]
pub struct BrowseQuery { pub struct BrowseQuery {
#[schema(default, example = 150)] #[schema(default, example = 150)]
#[deserr(default, error = DeserrJsonError<InvalidDocumentOffset>)] #[deserr(default, error = DeserrJsonError<InvalidDocumentOffset>)]
@ -409,13 +414,11 @@ pub struct BrowseQuery {
/// Get a set of documents. /// Get a set of documents.
#[utoipa::path( #[utoipa::path(
post, post,
path = "/{indexUid}/documents/fetch", path = "{indexUid}/documents/fetch",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.delete", "documents.*", "*"])), security(("Bearer" = ["documents.delete", "documents.*", "*"])),
params( params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)),
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), request_body = BrowseQuery,
BrowseQuery,
),
responses( responses(
(status = 200, description = "Task successfully enqueued", body = PaginationView<serde_json::Value>, content_type = "application/json", example = json!( (status = 200, description = "Task successfully enqueued", body = PaginationView<serde_json::Value>, content_type = "application/json", example = json!(
{ {
@ -486,8 +489,8 @@ pub async fn documents_by_query_post(
/// Get documents by batches. /// Get documents by batches.
#[utoipa::path( #[utoipa::path(
get, get,
path = "/{indexUid}/documents", path = "{indexUid}/documents",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.get", "documents.*", "*"])), security(("Bearer" = ["documents.get", "documents.*", "*"])),
params( params(
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false),
@ -607,7 +610,7 @@ fn documents_by_query(
#[derive(Deserialize, Debug, Deserr, IntoParams)] #[derive(Deserialize, 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")] #[into_params(parameter_in = Query, rename_all = "camelCase")]
pub struct UpdateDocumentsQuery { 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, /// 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. /// 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<Method: AggregateMethod> Aggregate for DocumentsAggregator<Method> {
/// > This object accepts keys corresponding to the different embedders defined your index settings. /// > This object accepts keys corresponding to the different embedders defined your index settings.
#[utoipa::path( #[utoipa::path(
post, post,
path = "/{indexUid}/documents", path = "{indexUid}/documents",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.add", "documents.*", "*"])), security(("Bearer" = ["documents.add", "documents.*", "*"])),
params( params(
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), ("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 // Here we can use the post version of the browse query since it contains the exact same parameter
UpdateDocumentsQuery, UpdateDocumentsQuery,
), ),
request_body = serde_json::Value,
responses( responses(
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( (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. /// > This object accepts keys corresponding to the different embedders defined your index settings.
#[utoipa::path( #[utoipa::path(
put, put,
path = "/{indexUid}/documents", path = "{indexUid}/documents",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.add", "documents.*", "*"])), security(("Bearer" = ["documents.add", "documents.*", "*"])),
params( params(
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), ("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 // Here we can use the post version of the browse query since it contains the exact same parameter
UpdateDocumentsQuery, UpdateDocumentsQuery,
), ),
request_body = serde_json::Value,
responses( responses(
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( (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) 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( #[utoipa::path(
delete, post,
path = "/{indexUid}/documents", path = "{indexUid}/delete-batch",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.delete", "documents.*", "*"])), security(("Bearer" = ["documents.delete", "documents.*", "*"])),
params( params(
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), ("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false),
// TODO: how to task an array of strings in parameter
), ),
request_body = Vec<Value>,
responses( responses(
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( (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)) Ok(HttpResponse::Accepted().json(task))
} }
#[derive(Debug, Deserr, IntoParams)] #[derive(Debug, Deserr, ToSchema)]
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)]
#[schema(rename_all = "camelCase")]
pub struct DocumentDeletionByFilter { pub struct DocumentDeletionByFilter {
#[deserr(error = DeserrJsonError<InvalidDocumentFilter>, missing_field_error = DeserrJsonError::missing_document_filter)] #[deserr(error = DeserrJsonError<InvalidDocumentFilter>, missing_field_error = DeserrJsonError::missing_document_filter)]
filter: Value, filter: Value,
@ -1128,15 +1134,13 @@ pub struct DocumentDeletionByFilter {
/// Delete a set of documents based on a filter. /// Delete a set of documents based on a filter.
#[utoipa::path( #[utoipa::path(
post, post,
path = "/{indexUid}/documents/delete", path = "{indexUid}/documents/delete",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.delete", "documents.*", "*"])), security(("Bearer" = ["documents.delete", "documents.*", "*"])),
params( params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)),
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), request_body = DocumentDeletionByFilter,
DocumentDeletionByFilter,
),
responses( 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, "taskUid": 147,
"indexUid": null, "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. /// Use a [RHAI function](https://rhai.rs/book/engine/hello-world.html) to edit one or more documents directly in Meilisearch.
#[utoipa::path( #[utoipa::path(
post, post,
path = "/{indexUid}/documents/edit", path = "{indexUid}/documents/edit",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.*", "*"])), security(("Bearer" = ["documents.*", "*"])),
params( params(
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false), ("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. /// Delete all documents in the specified index.
#[utoipa::path( #[utoipa::path(
delete, delete,
path = "/{indexUid}/documents", path = "{indexUid}/documents",
tags = ["Indexes", "Documents"], tag = "Documents",
security(("Bearer" = ["documents.delete", "documents.*", "*"])), security(("Bearer" = ["documents.delete", "documents.*", "*"])),
params( params(("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false)),
("indexUid", example = "movies", description = "Index Unique Identifier", nullable = false),
UpdateDocumentsQuery,
),
responses( responses(
(status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!( (status = 200, description = "Task successfully enqueued", body = SummarizedTaskView, content_type = "application/json", example = json!(
{ {

View File

@ -6,6 +6,7 @@ use crate::milli::progress::ProgressStepView;
use crate::milli::progress::ProgressView; use crate::milli::progress::ProgressView;
use crate::routes::batches::AllBatches; use crate::routes::batches::AllBatches;
use crate::routes::features::RuntimeTogglableFeatures; use crate::routes::features::RuntimeTogglableFeatures;
use crate::routes::indexes::documents::DocumentDeletionByFilter;
use crate::routes::indexes::documents::DocumentEditionByFunction; use crate::routes::indexes::documents::DocumentEditionByFunction;
use crate::routes::multi_search::SearchResults; use crate::routes::multi_search::SearchResults;
use crate::routes::swap_indexes::SwapIndexesPayload; 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."), (name = "Stats", description = "Stats gives extended information and metrics about indexes and the Meilisearch database."),
), ),
modifiers(&OpenApiAuth), modifiers(&OpenApiAuth),
components(schemas(AllBatches, BatchStats, ProgressStepView, ProgressView, BatchView, RuntimeTogglableFeatures, SwapIndexesPayload, DocumentEditionByFunction, MergeFacets, FederationOptions, SearchQueryWithIndex, Federation, FederatedSearch, FederatedSearchResult, SearchResults, SearchResultWithIndex, SimilarQuery, SimilarResult, PaginationView<serde_json::Value>, BrowseQuery, UpdateIndexRequest, IndexUid, IndexCreateRequest, KeyView, Action, CreateApiKey, UpdateStderrLogs, LogMode, GetLogs, IndexStats, Stats, HealthStatus, HealthResponse, VersionResponse, Code, ErrorType, AllTasks, TaskView, Status, DetailsView, ResponseError, Settings<Unchecked>, Settings<Checked>, 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<serde_json::Value>, BrowseQuery, UpdateIndexRequest, IndexUid, IndexCreateRequest, KeyView, Action, CreateApiKey, UpdateStderrLogs, LogMode, GetLogs, IndexStats, Stats, HealthStatus, HealthResponse, VersionResponse, Code, ErrorType, AllTasks, TaskView, Status, DetailsView, ResponseError, Settings<Unchecked>, Settings<Checked>, TypoSettings, MinWordSizeTyposSetting, FacetingSettings, PaginationSettings, SummarizedTaskView, Kind))
)] )]
pub struct MeilisearchApi; pub struct MeilisearchApi;