From fc8b6e0f9f4fc5455d58900a7c200be717b8c00c Mon Sep 17 00:00:00 2001 From: Mubelotix Date: Thu, 17 Jul 2025 07:51:15 +0200 Subject: [PATCH] Add doc loading --- crates/meilisearch-types/src/error.rs | 3 +- .../src/routes/indexes/documents.rs | 2 - .../meilisearch/src/routes/indexes/render.rs | 51 +++++++++++++++++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 4f06e4879..187b6dde0 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -423,7 +423,8 @@ InvalidRenderTemplateId , InvalidRequest , BAD_REQU InvalidRenderTemplateInline , InvalidRequest , BAD_REQUEST ; InvalidRenderInput , InvalidRequest , BAD_REQUEST ; InvalidRenderInputDocumentId , InvalidRequest , BAD_REQUEST ; -InvalidRenderInputInline , InvalidRequest , BAD_REQUEST +InvalidRenderInputInline , InvalidRequest , BAD_REQUEST ; +RenderDocumentNotFound , InvalidRequest , NOT_FOUND } impl ErrorCode for JoinError { diff --git a/crates/meilisearch/src/routes/indexes/documents.rs b/crates/meilisearch/src/routes/indexes/documents.rs index a93d736f7..bc5539081 100644 --- a/crates/meilisearch/src/routes/indexes/documents.rs +++ b/crates/meilisearch/src/routes/indexes/documents.rs @@ -1461,8 +1461,6 @@ fn some_documents<'a, 't: 'a>( document.remove("_vectors"); } RetrieveVectors::Retrieve => { - // Clippy is simply wrong - #[allow(clippy::manual_unwrap_or_default)] let mut vectors = match document.remove("_vectors") { Some(Value::Object(map)) => map, _ => Default::default(), diff --git a/crates/meilisearch/src/routes/indexes/render.rs b/crates/meilisearch/src/routes/indexes/render.rs index 0205777dd..c513218ae 100644 --- a/crates/meilisearch/src/routes/indexes/render.rs +++ b/crates/meilisearch/src/routes/indexes/render.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use actix_web::web::{self, Data}; use actix_web::{HttpRequest, HttpResponse}; use deserr::actix_web::{AwebJson, AwebQueryParameter}; @@ -6,12 +8,13 @@ use index_scheduler::IndexScheduler; use itertools::structs; use meilisearch_types::deserr::query_params::Param; use meilisearch_types::deserr::{DeserrJsonError, DeserrQueryParamError}; +use meilisearch_types::error::deserr_codes::{InvalidRenderInput, InvalidRenderInputDocumentId, InvalidRenderInputInline, InvalidRenderTemplate, InvalidRenderTemplateId, InvalidRenderTemplateInline}; use meilisearch_types::error::ResponseError; -use meilisearch_types::error::{deserr_codes::*, Code}; +use meilisearch_types::error::{Code}; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::keys::actions; use meilisearch_types::serde_cs::vec::CS; -use meilisearch_types::{heed, Index}; +use meilisearch_types::{heed, milli, Index}; use serde::Serialize; use serde_json::Value; use tracing::debug; @@ -19,6 +22,7 @@ use utoipa::{IntoParams, OpenApi, ToSchema}; use super::ActionPolicy; use crate::analytics::Analytics; +use crate::error::MeilisearchHttpError; use crate::extractors::authentication::GuardedData; use crate::extractors::sequential_extractor::SeqHandler; use crate::routes::indexes::similar_analytics::{SimilarAggregator, SimilarGET, SimilarPOST}; @@ -157,6 +161,9 @@ enum RenderError { LeftOverToken(String), MissingChatCompletionTemplate, UnknownChatCompletionTemplate(String), + + DocumentNotFound(String), + BothInlineDocAndDocId, } impl From for RenderError { @@ -165,6 +172,12 @@ impl From for RenderError { } } +impl From for RenderError { + fn from(error: milli::Error) -> Self { + RenderError::ReponseError(error.into()) + } +} + use RenderError::*; impl From for ResponseError { @@ -260,6 +273,14 @@ impl From for ResponseError { format!("Unknown chat completion template ID `{id}`. The only available template is `documentTemplate`."), Code::InvalidRenderTemplateId, ), + DocumentNotFound(doc_id) => ResponseError::from_msg( + format!("Document with ID `{doc_id}` not found."), + Code::RenderDocumentNotFound, + ), + BothInlineDocAndDocId => ResponseError::from_msg( + String::from("A document id was provided but adding it to the input would overwrite the `doc` field that you already defined inline."), + Code::InvalidRenderInput, + ), } } } @@ -396,6 +417,26 @@ async fn render(index: Index, query: RenderQuery) -> Result return Err(MissingTemplate), }; + let mut media = query.input.inline.unwrap_or_default(); + + if let Some(document_id) = query.input.document_id { + let internal_id = index + .external_documents_ids() + .get(&rtxn, &document_id)? + .ok_or_else(|| DocumentNotFound(document_id.to_string()))?; + + let document = index.document(&rtxn, internal_id)?; + + let fields_ids_map = index.fields_ids_map(&rtxn)?; + let all_fields: Vec<_> = fields_ids_map.iter().map(|(id, _)| id).collect(); + let document = milli::obkv_to_json(&all_fields, &fields_ids_map, document)?; + let document = Value::Object(document); + + if media.insert(String::from("doc"), document).is_some() { + return Err(BothInlineDocAndDocId); + } + } + Ok(RenderResult { template, rendered: String::from("TODO: Implement render logic here") }) } @@ -420,10 +461,10 @@ pub struct RenderQueryTemplate { #[derive(Debug, Clone, PartialEq, Deserr, ToSchema)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct RenderQueryInput { - #[deserr(default, error = DeserrJsonError)] + #[deserr(default, error = DeserrJsonError)] document_id: Option, - #[deserr(default, error = DeserrJsonError)] - inline: Option, + #[deserr(default, error = DeserrJsonError)] + inline: Option>, } #[derive(Debug, Clone, Serialize, PartialEq, ToSchema)]